marvisx-cli 0.1.0__py3-none-any.whl

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 (587) hide show
  1. core/api/__init__.py +0 -0
  2. core/api/agents/__init__.py +0 -0
  3. core/api/agents/session_health.py +59 -0
  4. core/api/agents/session_manager.py +206 -0
  5. core/api/bin/marvisx-state-hook.py +182 -0
  6. core/api/config.py +533 -0
  7. core/api/db.py +1516 -0
  8. core/api/dependencies/__init__.py +0 -0
  9. core/api/dependencies/tenant.py +34 -0
  10. core/api/main.py +1641 -0
  11. core/api/mcp/__init__.py +8 -0
  12. core/api/mcp/_adapter.py +184 -0
  13. core/api/mcp/server.py +58 -0
  14. core/api/mcp/tools/__init__.py +59 -0
  15. core/api/mcp/tools/brain.py +599 -0
  16. core/api/mcp/tools/graph.py +380 -0
  17. core/api/mcp/tools/handoffs.py +112 -0
  18. core/api/mcp/tools/ingest.py +326 -0
  19. core/api/mcp/tools/learnings.py +144 -0
  20. core/api/mcp/tools/projects.py +99 -0
  21. core/api/mcp/tools/pull_requests.py +173 -0
  22. core/api/mcp/tools/safety.py +111 -0
  23. core/api/mcp/tools/search.py +79 -0
  24. core/api/mcp/tools/tasks.py +258 -0
  25. core/api/middleware/__init__.py +0 -0
  26. core/api/middleware/tool_call_audit.py +111 -0
  27. core/api/models/__init__.py +346 -0
  28. core/api/models/auth.py +48 -0
  29. core/api/models/brain.py +1006 -0
  30. core/api/models/common.py +76 -0
  31. core/api/models/costs.py +91 -0
  32. core/api/models/graph.py +66 -0
  33. core/api/models/graph_cosmo.py +125 -0
  34. core/api/models/graph_pr_impact.py +257 -0
  35. core/api/models/graph_ux.py +141 -0
  36. core/api/models/inbox.py +230 -0
  37. core/api/models/ingest_keys.py +108 -0
  38. core/api/models/kg.py +41 -0
  39. core/api/models/llm_config.py +56 -0
  40. core/api/models/monitoring.py +234 -0
  41. core/api/models/projects.py +161 -0
  42. core/api/models/search.py +42 -0
  43. core/api/models/sessions.py +322 -0
  44. core/api/models/tasks.py +184 -0
  45. core/api/models/teams.py +63 -0
  46. core/api/models/users.py +184 -0
  47. core/api/observability/__init__.py +0 -0
  48. core/api/observability/tracing.py +92 -0
  49. core/api/paths.py +26 -0
  50. core/api/rate_limit.py +24 -0
  51. core/api/rbac.py +112 -0
  52. core/api/routers/__init__.py +0 -0
  53. core/api/routers/_adapter.py +24 -0
  54. core/api/routers/admin_pr_impact.py +230 -0
  55. core/api/routers/admin_settings.py +147 -0
  56. core/api/routers/agent.py +1079 -0
  57. core/api/routers/agent_tokens.py +276 -0
  58. core/api/routers/app_settings.py +112 -0
  59. core/api/routers/audit.py +89 -0
  60. core/api/routers/auth.py +586 -0
  61. core/api/routers/bench.py +161 -0
  62. core/api/routers/brain.py +881 -0
  63. core/api/routers/brain_directions.py +527 -0
  64. core/api/routers/ci_checks.py +140 -0
  65. core/api/routers/comments.py +273 -0
  66. core/api/routers/costs.py +148 -0
  67. core/api/routers/docs_coverage.py +217 -0
  68. core/api/routers/docs_governance.py +63 -0
  69. core/api/routers/documents.py +318 -0
  70. core/api/routers/files.py +163 -0
  71. core/api/routers/finder.py +987 -0
  72. core/api/routers/graph.py +836 -0
  73. core/api/routers/handoffs.py +156 -0
  74. core/api/routers/inbox.py +496 -0
  75. core/api/routers/ingest_api_keys.py +205 -0
  76. core/api/routers/ingest_triage.py +1227 -0
  77. core/api/routers/judge.py +306 -0
  78. core/api/routers/kg.py +336 -0
  79. core/api/routers/learnings.py +253 -0
  80. core/api/routers/llm_config.py +130 -0
  81. core/api/routers/monitoring.py +347 -0
  82. core/api/routers/notifications.py +125 -0
  83. core/api/routers/pr_impact.py +315 -0
  84. core/api/routers/projects.py +1061 -0
  85. core/api/routers/pull_requests.py +312 -0
  86. core/api/routers/push.py +67 -0
  87. core/api/routers/raci.py +228 -0
  88. core/api/routers/search.py +125 -0
  89. core/api/routers/sessions.py +3100 -0
  90. core/api/routers/settings.py +90 -0
  91. core/api/routers/share_repo.py +68 -0
  92. core/api/routers/status_updates.py +96 -0
  93. core/api/routers/tags.py +45 -0
  94. core/api/routers/tasks.py +526 -0
  95. core/api/routers/teams.py +425 -0
  96. core/api/routers/terminal.py +105 -0
  97. core/api/routers/users.py +331 -0
  98. core/api/routers/webhooks.py +330 -0
  99. core/api/runtime_settings.py +84 -0
  100. core/api/security.py +652 -0
  101. core/api/services/__init__.py +0 -0
  102. core/api/services/audit.py +58 -0
  103. core/api/services/auto_approval.py +82 -0
  104. core/api/services/brain/__init__.py +52 -0
  105. core/api/services/brain/baseline.py +230 -0
  106. core/api/services/brain/capabilities.py +75 -0
  107. core/api/services/brain/cascade_rollup.py +388 -0
  108. core/api/services/brain/compound_bridge.py +215 -0
  109. core/api/services/brain/cycle.py +1242 -0
  110. core/api/services/brain/cycle_snapshot.py +371 -0
  111. core/api/services/brain/digest_collector.py +147 -0
  112. core/api/services/brain/direction.py +421 -0
  113. core/api/services/brain/drift.py +356 -0
  114. core/api/services/brain/drift_router.py +409 -0
  115. core/api/services/brain/edge_metrics.py +79 -0
  116. core/api/services/brain/events_reader.py +222 -0
  117. core/api/services/brain/findings.py +1379 -0
  118. core/api/services/brain/findings_reader.py +1006 -0
  119. core/api/services/brain/jobs.py +733 -0
  120. core/api/services/brain/journal.py +206 -0
  121. core/api/services/brain/knowledge_forms.py +92 -0
  122. core/api/services/brain/llm/__init__.py +37 -0
  123. core/api/services/brain/llm/_runner.py +62 -0
  124. core/api/services/brain/llm/base.py +70 -0
  125. core/api/services/brain/llm/cache.py +99 -0
  126. core/api/services/brain/llm/constants.py +46 -0
  127. core/api/services/brain/llm/direction_alignment.py +289 -0
  128. core/api/services/brain/llm/factory.py +132 -0
  129. core/api/services/brain/llm/finding_reasoning.py +98 -0
  130. core/api/services/brain/llm/finding_summary.py +92 -0
  131. core/api/services/brain/llm/grounding.py +46 -0
  132. core/api/services/brain/llm/journal_polish.py +96 -0
  133. core/api/services/brain/llm/local_gateway.py +426 -0
  134. core/api/services/brain/llm/parsers.py +71 -0
  135. core/api/services/brain/llm/router_glue.py +422 -0
  136. core/api/services/brain/memory_ops.py +1677 -0
  137. core/api/services/brain/models.py +140 -0
  138. core/api/services/brain/owner_hint.py +211 -0
  139. core/api/services/brain/recap.py +307 -0
  140. core/api/services/brain/rules/__init__.py +65 -0
  141. core/api/services/brain/rules/_signals.py +205 -0
  142. core/api/services/brain/rules/dr1_activity_without_status.py +108 -0
  143. core/api/services/brain/rules/dr2_decision_without_adr.py +110 -0
  144. core/api/services/brain/rules/dr3_stale_open_loop.py +127 -0
  145. core/api/services/brain/rules/dr4_docs_governance_drift.py +79 -0
  146. core/api/services/brain/rules/dr5_playbook_changed.py +99 -0
  147. core/api/services/brain/rules/dr6_external_update_unpropagated.py +100 -0
  148. core/api/services/brain/rules/dr7_claimed_decision_gap.py +123 -0
  149. core/api/services/brain/rules/dr8_direction_misalignment.py +230 -0
  150. core/api/services/brain/runs_reader.py +485 -0
  151. core/api/services/brain/scope.py +79 -0
  152. core/api/services/brain/sources/__init__.py +46 -0
  153. core/api/services/brain/sources/base.py +86 -0
  154. core/api/services/brain/sources/git_kg.py +393 -0
  155. core/api/services/brain/sources/handoffs.py +157 -0
  156. core/api/services/brain/sources/ingestor.py +130 -0
  157. core/api/services/brain/sources/learnings.py +121 -0
  158. core/api/services/brain/sources/pir_tasks.py +245 -0
  159. core/api/services/brain/watermarks.py +147 -0
  160. core/api/services/brain/ws_emitter.py +170 -0
  161. core/api/services/cc_tasks_reader.py +76 -0
  162. core/api/services/ci_service.py +263 -0
  163. core/api/services/claude_metrics.py +796 -0
  164. core/api/services/codex_metrics.py +364 -0
  165. core/api/services/conversation_reader.py +102 -0
  166. core/api/services/cost_service.py +243 -0
  167. core/api/services/crypto.py +147 -0
  168. core/api/services/docs_governance/__init__.py +1 -0
  169. core/api/services/docs_governance/confidence.py +230 -0
  170. core/api/services/docs_governance/config.py +87 -0
  171. core/api/services/docs_governance/enrichment.py +65 -0
  172. core/api/services/docs_governance/frontmatter_validator.py +83 -0
  173. core/api/services/docs_governance/hard_gates.py +221 -0
  174. core/api/services/docs_governance/triage_orchestrator.py +98 -0
  175. core/api/services/embedding_internal.py +395 -0
  176. core/api/services/embedding_service.py +832 -0
  177. core/api/services/event_dispatcher.py +167 -0
  178. core/api/services/events.py +70 -0
  179. core/api/services/git_ops.py +621 -0
  180. core/api/services/graph_cosmo_service.py +440 -0
  181. core/api/services/graph_ranker.py +306 -0
  182. core/api/services/graph_service.py +1589 -0
  183. core/api/services/inbox.py +800 -0
  184. core/api/services/inbox_digest.py +221 -0
  185. core/api/services/inbox_digest_deep_research.py +80 -0
  186. core/api/services/inbox_digest_jobs.py +595 -0
  187. core/api/services/inbox_gmail_sync.py +167 -0
  188. core/api/services/inbox_llm_classifier.py +906 -0
  189. core/api/services/inbox_source_identity.py +116 -0
  190. core/api/services/inbox_sources.py +456 -0
  191. core/api/services/inbox_taxonomy.py +195 -0
  192. core/api/services/inbox_tldr.py +1079 -0
  193. core/api/services/inbox_triage.py +899 -0
  194. core/api/services/ingest/__init__.py +13 -0
  195. core/api/services/ingest/api_key_auth.py +136 -0
  196. core/api/services/ingest/auto_approve.py +120 -0
  197. core/api/services/ingest/classifier.py +138 -0
  198. core/api/services/ingest/confidence.py +173 -0
  199. core/api/services/ingest/dispatch.py +88 -0
  200. core/api/services/ingest/embedding_router.py +272 -0
  201. core/api/services/ingest/events.py +33 -0
  202. core/api/services/ingest/ignore_patterns.py +79 -0
  203. core/api/services/ingest/image_probe.py +218 -0
  204. core/api/services/ingest/ingress.py +263 -0
  205. core/api/services/ingest/insert_saga.py +793 -0
  206. core/api/services/ingest/llm/__init__.py +13 -0
  207. core/api/services/ingest/llm/anthropic_haiku.py +23 -0
  208. core/api/services/ingest/llm/base.py +59 -0
  209. core/api/services/ingest/llm/byok_provider.py +130 -0
  210. core/api/services/ingest/llm/classification_context.py +301 -0
  211. core/api/services/ingest/llm/config_store.py +246 -0
  212. core/api/services/ingest/llm/factory.py +24 -0
  213. core/api/services/ingest/llm/kg_enricher.py +306 -0
  214. core/api/services/ingest/llm/local_gateway.py +821 -0
  215. core/api/services/ingest/llm/local_vllm.py +23 -0
  216. core/api/services/ingest/llm/openai_nano.py +349 -0
  217. core/api/services/ingest/lock_advisory.py +57 -0
  218. core/api/services/ingest/parser_router.py +1756 -0
  219. core/api/services/ingest/parsers/__init__.py +1 -0
  220. core/api/services/ingest/parsers/docling_parser.py +142 -0
  221. core/api/services/ingest/parsers/docparse_gateway.py +178 -0
  222. core/api/services/ingest/parsers/docx_parser.py +127 -0
  223. core/api/services/ingest/parsers/folder_unpacker.py +85 -0
  224. core/api/services/ingest/parsers/gateway_aux.py +147 -0
  225. core/api/services/ingest/parsers/image_parser.py +251 -0
  226. core/api/services/ingest/parsers/internal_markdown.py +89 -0
  227. core/api/services/ingest/parsers/ocr_gateway.py +117 -0
  228. core/api/services/ingest/parsers/ocr_pdf_parser.py +112 -0
  229. core/api/services/ingest/parsers/pdf_types.py +13 -0
  230. core/api/services/ingest/parsers/transcript_parser.py +445 -0
  231. core/api/services/ingest/parsers/vision_gateway.py +186 -0
  232. core/api/services/ingest/parsers/xlsx_parser.py +91 -0
  233. core/api/services/ingest/parsers/zip_unpacker.py +126 -0
  234. core/api/services/ingest/preflight.py +393 -0
  235. core/api/services/ingest/retry_voyage.py +88 -0
  236. core/api/services/ingest/routing_policy.py +307 -0
  237. core/api/services/ingest/serializers/__init__.py +1 -0
  238. core/api/services/ingest/serializers/xlsx_to_markdown.py +80 -0
  239. core/api/services/ingest/skip_log.py +74 -0
  240. core/api/services/ingest/watcher.py +637 -0
  241. core/api/services/kg/__init__.py +0 -0
  242. core/api/services/kg/audit.py +49 -0
  243. core/api/services/kg/hybrid_search.py +691 -0
  244. core/api/services/kg/lens.py +339 -0
  245. core/api/services/kg/pr_impact.py +770 -0
  246. core/api/services/kg/queries.py +152 -0
  247. core/api/services/kg/ranking.py +89 -0
  248. core/api/services/kg/rrf.py +143 -0
  249. core/api/services/kg_watcher_control.py +161 -0
  250. core/api/services/local_llm/__init__.py +19 -0
  251. core/api/services/local_llm/async_client.py +385 -0
  252. core/api/services/local_llm/client.py +173 -0
  253. core/api/services/local_llm/url_validator.py +44 -0
  254. core/api/services/metrics_collector.py +646 -0
  255. core/api/services/metrics_providers.py +65 -0
  256. core/api/services/model_registry.py +266 -0
  257. core/api/services/model_router.py +137 -0
  258. core/api/services/n8n_client.py +77 -0
  259. core/api/services/newsletter_llm_gateway.py +66 -0
  260. core/api/services/notification_service.py +134 -0
  261. core/api/services/openai_responses.py +55 -0
  262. core/api/services/opencode_metrics.py +375 -0
  263. core/api/services/opencode_sessions.py +173 -0
  264. core/api/services/pii_redactor.py +138 -0
  265. core/api/services/pr_impact_pipeline/__init__.py +21 -0
  266. core/api/services/pr_impact_pipeline/differ.py +421 -0
  267. core/api/services/pr_impact_pipeline/dispatcher.py +415 -0
  268. core/api/services/pr_impact_pipeline/gc.py +93 -0
  269. core/api/services/pr_impact_pipeline/languages.py +192 -0
  270. core/api/services/pr_impact_pipeline/parser.py +178 -0
  271. core/api/services/pr_impact_pipeline/writer.py +394 -0
  272. core/api/services/pr_service.py +1393 -0
  273. core/api/services/project_paths.py +70 -0
  274. core/api/services/project_status_updates.py +265 -0
  275. core/api/services/providers.py +276 -0
  276. core/api/services/push_service.py +170 -0
  277. core/api/services/reminder_service.py +89 -0
  278. core/api/services/runas.py +41 -0
  279. core/api/services/salience_service.py +69 -0
  280. core/api/services/security_collector.py +281 -0
  281. core/api/services/session_catalog.py +385 -0
  282. core/api/services/session_metrics_service.py +301 -0
  283. core/api/services/session_ops.py +272 -0
  284. core/api/services/session_state.py +173 -0
  285. core/api/services/share_links.py +222 -0
  286. core/api/services/task_transitions.py +146 -0
  287. core/api/services/terminal_metrics.py +462 -0
  288. core/api/services/terminal_metrics_dump.py +203 -0
  289. core/api/services/tmux.py +1205 -0
  290. core/api/services/webhook_service.py +422 -0
  291. core/api/services/workspace_sync.py +164 -0
  292. core/api/templates/__init__.py +1 -0
  293. core/api/templates/markdown_share.py +164 -0
  294. core/api/terminal.py +1031 -0
  295. core/api/tests/__init__.py +0 -0
  296. core/api/tests/test_agent_facing_auth_dependencies.py +132 -0
  297. core/api/tests/test_audit_permissions.py +133 -0
  298. core/api/tests/test_backfill_session_conversations.py +90 -0
  299. core/api/tests/test_backfill_working_seconds_msg.py +129 -0
  300. core/api/tests/test_claude_metrics.py +326 -0
  301. core/api/tests/test_codex_metrics.py +189 -0
  302. core/api/tests/test_finder_paths.py +74 -0
  303. core/api/tests/test_git_ops_merge.py +155 -0
  304. core/api/tests/test_learnings_check_search.py +81 -0
  305. core/api/tests/test_metrics_providers.py +133 -0
  306. core/api/tests/test_migration_087.py +164 -0
  307. core/api/tests/test_migration_088.py +94 -0
  308. core/api/tests/test_migration_089.py +116 -0
  309. core/api/tests/test_openai_responses.py +24 -0
  310. core/api/tests/test_opencode_metrics.py +740 -0
  311. core/api/tests/test_opencode_sessions.py +321 -0
  312. core/api/tests/test_pr_workflow_e2e.py +457 -0
  313. core/api/tests/test_projects_handoffs.py +31 -0
  314. core/api/tests/test_providers.py +138 -0
  315. core/api/tests/test_safety_bridge.py +347 -0
  316. core/api/tests/test_session_catalog.py +142 -0
  317. core/api/tests/test_session_conversations.py +512 -0
  318. core/api/tests/test_session_metrics_service.py +270 -0
  319. core/api/tests/test_session_resume_paths.py +548 -0
  320. core/api/tests/test_session_theme_mode_migration.py +56 -0
  321. core/api/tests/test_sessions_rbac.py +131 -0
  322. core/api/tests/test_share_edit.py +398 -0
  323. core/api/tests/test_share_repo.py +200 -0
  324. core/api/tests/test_terminal_session_manager.py +98 -0
  325. core/api/tests/test_terminal_upload.py +34 -0
  326. core/api/tests/test_tmux.py +272 -0
  327. core/api/tests/test_workspace_sync.py +186 -0
  328. core/api/tests/test_ws_ticket_in_memory.py +73 -0
  329. core/api/use_cases/__init__.py +11 -0
  330. core/api/use_cases/_context.py +89 -0
  331. core/api/use_cases/_errors.py +62 -0
  332. core/api/use_cases/_roles.py +16 -0
  333. core/api/use_cases/audit.py +171 -0
  334. core/api/use_cases/brain.py +1232 -0
  335. core/api/use_cases/costs.py +249 -0
  336. core/api/use_cases/graph.py +1153 -0
  337. core/api/use_cases/handoffs.py +506 -0
  338. core/api/use_cases/ingest_triage.py +1229 -0
  339. core/api/use_cases/learnings.py +538 -0
  340. core/api/use_cases/projects.py +705 -0
  341. core/api/use_cases/pull_requests.py +415 -0
  342. core/api/use_cases/search.py +926 -0
  343. core/api/use_cases/tasks.py +1495 -0
  344. core/api/visibility.py +141 -0
  345. core/cli/__init__.py +5 -0
  346. core/cli/_index_source.py +632 -0
  347. core/cli/_runtime_ctx.py +160 -0
  348. core/cli/_transmute.py +241 -0
  349. core/cli/marvis_doctor.py +704 -0
  350. core/cli/marvis_feedback.py +396 -0
  351. core/cli/marvis_governance.py +315 -0
  352. core/cli/marvis_hooks.py +515 -0
  353. core/cli/marvis_init.py +757 -0
  354. core/cli/marvis_mcp.py +401 -0
  355. core/cli/marvis_runtime.py +855 -0
  356. core/cli/marvis_telemetry.py +228 -0
  357. core/scripts/_drift_check.py +716 -0
  358. core/scripts/_frontmatter.py +66 -0
  359. core/scripts/_graph_writer.py +189 -0
  360. core/scripts/ast_parser.py +1553 -0
  361. core/scripts/install_hooks/__init__.py +1 -0
  362. core/scripts/install_hooks/_config.sh +109 -0
  363. core/scripts/install_hooks/block-dangerous-bash.sh +23 -0
  364. core/scripts/install_hooks/block-db-direct-write.sh +23 -0
  365. core/scripts/install_hooks/block-push-no-task.sh +23 -0
  366. core/scripts/install_hooks/block-staging-to-prod.sh +23 -0
  367. core/scripts/install_hooks/block-subtree-push.sh +23 -0
  368. core/scripts/install_hooks/config.json +53 -0
  369. core/scripts/install_hooks/enforce-no-merge-main.sh +23 -0
  370. core/scripts/install_hooks/enforce-worktree.sh +23 -0
  371. core/scripts/install_hooks/quality-gate.sh +170 -0
  372. core/scripts/install_hooks/safety_bridge.py +968 -0
  373. core/scripts/install_hooks/secret-scan.sh +23 -0
  374. core/scripts/migrate_spike_node_ids.py +122 -0
  375. core/scripts/populate_artifacts.py +2198 -0
  376. core/scripts/populate_cross_project.py +2457 -0
  377. core/scripts/populate_inbox_nodes.py +357 -0
  378. core/scripts/populate_pr_impact.py +267 -0
  379. core/scripts/populate_project_nodes.py +603 -0
  380. core/scripts/populate_touch_counter.py +337 -0
  381. core/scripts/reparse_failed.py +57 -0
  382. core/scripts/safety_bridge.py +968 -0
  383. core/telemetry/__init__.py +9 -0
  384. core/telemetry/client.py +405 -0
  385. core/telemetry/schema.py +122 -0
  386. core/wizard/__init__.py +65 -0
  387. core/wizard/byok_vault.py +147 -0
  388. core/wizard/defaults.py +58 -0
  389. core/wizard/state.py +117 -0
  390. core/wizard/steps.py +70 -0
  391. core/wizard/validation.py +136 -0
  392. marvisx_cli-0.1.0.dist-info/METADATA +201 -0
  393. marvisx_cli-0.1.0.dist-info/RECORD +587 -0
  394. marvisx_cli-0.1.0.dist-info/WHEEL +5 -0
  395. marvisx_cli-0.1.0.dist-info/entry_points.txt +3 -0
  396. marvisx_cli-0.1.0.dist-info/licenses/LICENSE +98 -0
  397. marvisx_cli-0.1.0.dist-info/top_level.txt +3 -0
  398. migrations/001_initial.sql +33 -0
  399. migrations/002_tasks.sql +30 -0
  400. migrations/003_session_management.sql +7 -0
  401. migrations/004_projects_comments.sql +65 -0
  402. migrations/005_session_intelligence.sql +15 -0
  403. migrations/006_settings.sql +12 -0
  404. migrations/007_task_scoring.sql +12 -0
  405. migrations/008_cost_tracking.sql +31 -0
  406. migrations/009_session_card_metrics.sql +3 -0
  407. migrations/010_monitoring.sql +55 -0
  408. migrations/012_agent_api.sql +21 -0
  409. migrations/013_session_complete.sql +8 -0
  410. migrations/015_pull_requests.sql +43 -0
  411. migrations/015_pull_requests_down.sql +5 -0
  412. migrations/016_users_raci.sql +116 -0
  413. migrations/017_task_cost_entries.sql +87 -0
  414. migrations/018_agents.sql +73 -0
  415. migrations/018_agents_down.sql +13 -0
  416. migrations/019_review_feedback.sql +18 -0
  417. migrations/020_pr_commit_sha.sql +4 -0
  418. migrations/021_webhook_events.sql +18 -0
  419. migrations/022_devx_agent_managed.sql +11 -0
  420. migrations/022_devx_agent_managed_down.sql +6 -0
  421. migrations/023_devx_p1_gate.sql +7 -0
  422. migrations/023_devx_p1_gate_down.sql +3 -0
  423. migrations/024_chat_messages.sql +16 -0
  424. migrations/024_pr_conversation_id.sql +8 -0
  425. migrations/024_task_indexes.sql +21 -0
  426. migrations/024_task_indexes_down.sql +7 -0
  427. migrations/025_audit_log.sql +17 -0
  428. migrations/026_agent_tokens.sql +20 -0
  429. migrations/027_teams_auth_phase_b.sql +35 -0
  430. migrations/028_learnings.sql +23 -0
  431. migrations/029_team_roles.sql +14 -0
  432. migrations/030_finder_pins.sql +10 -0
  433. migrations/031_pr_deploy_status.sql +9 -0
  434. migrations/032_task_reminders.sql +7 -0
  435. migrations/033_events_retry_count.sql +6 -0
  436. migrations/033_session_owner.sql +9 -0
  437. migrations/034_notifications.sql +38 -0
  438. migrations/035_shared_links.sql +15 -0
  439. migrations/036_session_index_upgrade.sql +29 -0
  440. migrations/037_pr_approval.sql +15 -0
  441. migrations/038_pr_submitted_by.sql +6 -0
  442. migrations/039_push_subscriptions.sql +17 -0
  443. migrations/040_semantic_search.sql +16 -0
  444. migrations/041_workspaces.sql +63 -0
  445. migrations/042_oidc_providers.sql +24 -0
  446. migrations/043_ci_checks.sql +31 -0
  447. migrations/044_agent_metrics.sql +30 -0
  448. migrations/045_documents_doc_type.sql +5 -0
  449. migrations/046_salience.sql +13 -0
  450. migrations/047_seed_missing_agents.sql +6 -0
  451. migrations/048_fix_agent_paths_roles.sql +5 -0
  452. migrations/049_agent_role_and_learnings_schema.sql +3 -0
  453. migrations/050_session_provider.sql +2 -0
  454. migrations/051_session_launch_profile.sql +4 -0
  455. migrations/052_session_theme_mode.sql +2 -0
  456. migrations/052_task_kind.sql +4 -0
  457. migrations/053_inbox_items.sql +31 -0
  458. migrations/054_inbox_triage_contract.sql +30 -0
  459. migrations/055_inbox_topic_treatment.sql +12 -0
  460. migrations/056_inbox_treatment_read_save.sql +57 -0
  461. migrations/057_session_theme_mode_backfill.sql +4 -0
  462. migrations/058_inbox_item_status_lifecycle.sql +13 -0
  463. migrations/059_inbox_tldr_and_source_scores.sql +18 -0
  464. migrations/060_newsletter.sql +16 -0
  465. migrations/061_inbox_redesign.sql +69 -0
  466. migrations/062_fix_inbox_sources_backfill.sql +37 -0
  467. migrations/063_task_completion_mode.sql +23 -0
  468. migrations/064_judge_mode_setting.sql +4 -0
  469. migrations/065_knowledge_graph_spike.sql +40 -0
  470. migrations/066_digest_ranking_inputs.sql +10 -0
  471. migrations/066_kg_artifact_nodes.sql +129 -0
  472. migrations/067_inbox_digest_selections.sql +28 -0
  473. migrations/067_kg_temporal.sql +53 -0
  474. migrations/068_inbox_digest_app_settings.sql +9 -0
  475. migrations/068_kg_touch_counter.sql +52 -0
  476. migrations/069_kg_doc_types.sql +117 -0
  477. migrations/070_digest_ranking_inputs_recovery.sql +3 -0
  478. migrations/071_inbox_digest_selections_recovery.sql +3 -0
  479. migrations/072_inbox_digest_app_settings_recovery.sql +3 -0
  480. migrations/073_kg_cross_project.sql +216 -0
  481. migrations/073_kg_cross_project_down.sql +77 -0
  482. migrations/074_kg_infra_types.sql +208 -0
  483. migrations/074_kg_infra_types_down.sql +80 -0
  484. migrations/075_kg_file_state_recovery.sql +35 -0
  485. migrations/075_kg_file_state_recovery_down.sql +5 -0
  486. migrations/076_kg_watcher_state.sql +33 -0
  487. migrations/076_kg_watcher_state_down.sql +3 -0
  488. migrations/077_kg_doc_types_extend.sql +226 -0
  489. migrations/077_kg_doc_types_extend_down.sql +80 -0
  490. migrations/078_kg_fts5.sql +102 -0
  491. migrations/078_kg_fts5_down.sql +14 -0
  492. migrations/079_kg_missing_indexes.sql +31 -0
  493. migrations/079_kg_missing_indexes_down.sql +10 -0
  494. migrations/080_kg_fts5_extended.sql +232 -0
  495. migrations/080_kg_fts5_extended_down.sql +25 -0
  496. migrations/081_kg_lens_indexes.sql +9 -0
  497. migrations/081_kg_lens_indexes_down.sql +3 -0
  498. migrations/082_kg_pins.sql +26 -0
  499. migrations/082_kg_pins_down.sql +14 -0
  500. migrations/083_kg_graph_nodes_degree.sql +20 -0
  501. migrations/083_kg_graph_nodes_degree_down.sql +15 -0
  502. migrations/084_drop_legacy_scheduler_tables.sql +58 -0
  503. migrations/084_drop_legacy_scheduler_tables_down.sql +112 -0
  504. migrations/085_kg_edge_resolves_to.sql +142 -0
  505. migrations/085_kg_edge_resolves_to_down.sql +66 -0
  506. migrations/086_project_status_updates_feed.sql +20 -0
  507. migrations/086_project_status_updates_feed_down.sql +36 -0
  508. migrations/087_session_metrics_dual.sql +50 -0
  509. migrations/087_session_metrics_dual_down.sql +21 -0
  510. migrations/088_rename_context_pct_legacy.sql +23 -0
  511. migrations/088_rename_context_pct_legacy_down.sql +8 -0
  512. migrations/089_session_metrics_equivalent_cost.sql +26 -0
  513. migrations/089_session_metrics_equivalent_cost_down.sql +11 -0
  514. migrations/090_kg_inbox_node_type.sql +26 -0
  515. migrations/090_kg_inbox_node_type_down.sql +20 -0
  516. migrations/091_kg_inbox_node_type_check.sql +265 -0
  517. migrations/091_kg_inbox_node_type_check_down.sql +129 -0
  518. migrations/092_sessions_activity_state_ts.sql +29 -0
  519. migrations/092_sessions_activity_state_ts_down.sql +14 -0
  520. migrations/093_sessions_activity_state_column.sql +29 -0
  521. migrations/093_sessions_activity_state_column_down.sql +10 -0
  522. migrations/094_ingest_pending.sql +55 -0
  523. migrations/094_ingest_pending_down.sql +15 -0
  524. migrations/095_kg_intent_first.sql +77 -0
  525. migrations/095_kg_intent_first_down.sql +25 -0
  526. migrations/096_kg_xlsx_artifact_prefix.sql +17 -0
  527. migrations/096_kg_xlsx_artifact_prefix_down.sql +11 -0
  528. migrations/097_ingest_change_history.sql +37 -0
  529. migrations/097_ingest_change_history_down.sql +13 -0
  530. migrations/098_kg_node_type_business.sql +254 -0
  531. migrations/098_kg_node_type_business_down.sql +195 -0
  532. migrations/099_kg_edges_restore_weight.sql +58 -0
  533. migrations/099_kg_edges_restore_weight_down.sql +12 -0
  534. migrations/100_kg_enriched_at.sql +25 -0
  535. migrations/100_kg_enriched_at_down.sql +12 -0
  536. migrations/101_local_llm_shadow_comparisons.sql +66 -0
  537. migrations/101_local_llm_shadow_comparisons_down.sql +15 -0
  538. migrations/102_promote_llm_costs.sql +69 -0
  539. migrations/102_promote_llm_costs_down.sql +19 -0
  540. migrations/103_ingest_skipped_log.sql +46 -0
  541. migrations/103_ingest_skipped_log_down.sql +15 -0
  542. migrations/120_docs_governance.sql +50 -0
  543. migrations/120_docs_governance_down.sql +11 -0
  544. migrations/121_notification_event_fk_cleanup.sql +21 -0
  545. migrations/121_notification_event_fk_cleanup_down.sql +10 -0
  546. migrations/122_docs_drift_history.sql +34 -0
  547. migrations/122_docs_drift_history_down.sql +15 -0
  548. migrations/123_ingest_parser_waiting_status.sql +69 -0
  549. migrations/123_ingest_parser_waiting_status_down.sql +69 -0
  550. migrations/124_heypocket_recordings.sql +63 -0
  551. migrations/124_heypocket_recordings_down.sql +13 -0
  552. migrations/125_kg_node_type_record.sql +219 -0
  553. migrations/125_kg_node_type_record_down.sql +205 -0
  554. migrations/126_ingest_terminal_upload_source_kind.sql +69 -0
  555. migrations/126_ingest_terminal_upload_source_kind_down.sql +69 -0
  556. migrations/127_brain_v1_substrate.sql +200 -0
  557. migrations/127_brain_v1_substrate_down.sql +32 -0
  558. migrations/128_brain_drift_signals.sql +157 -0
  559. migrations/128_brain_drift_signals_down.sql +23 -0
  560. migrations/129_brain_memory_operations.sql +232 -0
  561. migrations/129_brain_memory_operations_down.sql +27 -0
  562. migrations/130_brain_findings.sql +258 -0
  563. migrations/130_brain_findings_down.sql +29 -0
  564. migrations/132_kg_pr_modifies.sql +242 -0
  565. migrations/132_kg_pr_modifies_down.sql +99 -0
  566. migrations/133_brain_v1_2_direction_schema.sql +476 -0
  567. migrations/133_brain_v1_2_direction_schema_down.sql +273 -0
  568. migrations/134_brain_journal_narrative_polished.sql +8 -0
  569. migrations/134_brain_journal_narrative_polished_down.sql +6 -0
  570. migrations/135_kg_edges_provider.sql +21 -0
  571. migrations/136_documents_fts.sql +56 -0
  572. migrations/137_promote_llm_costs.sql +59 -0
  573. migrations/137_promote_llm_costs_down.sql +19 -0
  574. migrations/138_ingest_api_keys.sql +39 -0
  575. migrations/138_ingest_api_keys_down.sql +8 -0
  576. migrations/139_ingest_pending_ingress.sql +91 -0
  577. migrations/139_ingest_pending_ingress_down.sql +73 -0
  578. migrations/140_ingest_idempotency_quota.sql +45 -0
  579. migrations/140_ingest_idempotency_quota_down.sql +9 -0
  580. migrations/141_ingest_pending_metadata.sql +16 -0
  581. migrations/141_ingest_pending_metadata_down.sql +7 -0
  582. migrations/142_llm_function_config.sql +36 -0
  583. migrations/142_llm_function_config_down.sql +8 -0
  584. migrations/143_kg_code_embeddings.sql +25 -0
  585. migrations/143_kg_code_embeddings_down.sql +5 -0
  586. migrations/__init__.py +4 -0
  587. projects/_template/project.yaml +46 -0
@@ -0,0 +1,273 @@
1
+ -- Migration 133 DOWN: Revert Brain v1.2 Direction Integration schema
2
+ -- Date: 2026-05-18
3
+ --
4
+ -- WARNING: Down migration may lose data if production rows used new enum
5
+ -- values (direction_drift / direction_bootstrap finding_type, DR8 rule_id,
6
+ -- direction_misalignment signal_type, pending_bootstrap / applied
7
+ -- approval_state). The down script will REMOVE such rows before swap.
8
+
9
+ PRAGMA foreign_keys = OFF;
10
+
11
+ BEGIN IMMEDIATE;
12
+
13
+ -- =============================================================================
14
+ -- 1. Drop new tables
15
+ -- =============================================================================
16
+ DROP TABLE IF EXISTS direction_changelog;
17
+ DROP TRIGGER IF EXISTS trg_project_directions_updated_at;
18
+ DROP TABLE IF EXISTS project_directions;
19
+
20
+ -- =============================================================================
21
+ -- 2. Revert brain_findings (remove new enum values + new columns)
22
+ -- =============================================================================
23
+
24
+ -- Remove rows that depend on new enum values (data loss accepted on rollback)
25
+ DELETE FROM brain_findings
26
+ WHERE finding_type IN ('direction_drift', 'direction_bootstrap')
27
+ OR approval_state IN ('pending_bootstrap', 'applied');
28
+
29
+ DROP TRIGGER IF EXISTS trg_brain_findings_updated_at;
30
+ DROP TRIGGER IF EXISTS trg_brain_findings_no_delete_resolved;
31
+ DROP TRIGGER IF EXISTS trg_brain_findings_terminal_forward_only;
32
+
33
+ DROP INDEX IF EXISTS uk_brain_findings_natural;
34
+ DROP INDEX IF EXISTS idx_brain_findings_scope_cycle;
35
+ DROP INDEX IF EXISTS idx_brain_findings_open;
36
+ DROP INDEX IF EXISTS idx_brain_findings_fingerprint;
37
+ DROP INDEX IF EXISTS idx_brain_findings_type_cycle;
38
+ DROP INDEX IF EXISTS idx_brain_findings_run;
39
+ DROP INDEX IF EXISTS idx_brain_findings_regression;
40
+ DROP INDEX IF EXISTS idx_brain_findings_entity_open;
41
+ DROP INDEX IF EXISTS idx_brain_findings_urgency;
42
+
43
+ CREATE TABLE brain_findings_old (
44
+ finding_id TEXT PRIMARY KEY,
45
+ run_id TEXT NOT NULL,
46
+ cycle_key TEXT NOT NULL,
47
+ detected_at TEXT NOT NULL
48
+ CHECK(detected_at LIKE '%Z' OR detected_at LIKE '%+00:00'),
49
+ finding_type TEXT NOT NULL
50
+ CHECK(finding_type IN (
51
+ 'idea','task_candidate','open_question',
52
+ 'scope_gap','procedure_change','contradiction'
53
+ )),
54
+ schema_version INTEGER NOT NULL DEFAULT 1,
55
+ scope_type TEXT NOT NULL
56
+ CHECK(scope_type IN ('company','program','project','artifact')),
57
+ scope_key TEXT NOT NULL,
58
+ program_key TEXT,
59
+ title TEXT NOT NULL CHECK(length(title) <= 200),
60
+ summary TEXT NOT NULL CHECK(length(summary) <= 2000),
61
+ why_now TEXT NOT NULL CHECK(length(why_now) <= 500),
62
+ evidence_hash TEXT NOT NULL CHECK(length(evidence_hash) = 64),
63
+ involved_projects_json TEXT NOT NULL DEFAULT '[]' CHECK(json_valid(involved_projects_json)),
64
+ suggested_artifact TEXT NOT NULL
65
+ CHECK(suggested_artifact IN (
66
+ 'task','adr','guide','learning','status_update','question','none'
67
+ )),
68
+ owner_hint_json TEXT NOT NULL DEFAULT '{}' CHECK(json_valid(owner_hint_json)),
69
+ closure_condition_kind TEXT NOT NULL
70
+ CHECK(closure_condition_kind IN (
71
+ 'drift_signal_clears','memory_op_applied','artifact_exists','manual_attest'
72
+ )),
73
+ closure_condition_json TEXT NOT NULL DEFAULT '{}' CHECK(json_valid(closure_condition_json)),
74
+ closure_condition_human TEXT CHECK(closure_condition_human IS NULL OR length(closure_condition_human) <= 500),
75
+ severity TEXT NOT NULL CHECK(severity IN ('low','medium','high','critical')),
76
+ confidence TEXT NOT NULL CHECK(confidence IN ('low','medium','high')),
77
+ approval_state TEXT NOT NULL DEFAULT 'open'
78
+ CHECK(approval_state IN ('open','approved','dismissed','resolved','superseded','expired')),
79
+ regression_of_finding_id TEXT,
80
+ proposal_fingerprint TEXT NOT NULL CHECK(length(proposal_fingerprint) = 32),
81
+ recurrence_count INTEGER NOT NULL DEFAULT 1 CHECK(recurrence_count >= 1),
82
+ first_seen_cycle_key TEXT NOT NULL,
83
+ last_seen_cycle_key TEXT NOT NULL,
84
+ applied_artifact_ref TEXT,
85
+ applied_at TEXT,
86
+ applied_by_user_id TEXT,
87
+ expires_at TEXT NOT NULL,
88
+ superseded_by_finding_id TEXT,
89
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
90
+ updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
91
+ FOREIGN KEY (run_id) REFERENCES brain_runs(run_id) ON DELETE RESTRICT,
92
+ FOREIGN KEY (regression_of_finding_id) REFERENCES brain_findings_old(finding_id) ON DELETE SET NULL,
93
+ FOREIGN KEY (superseded_by_finding_id) REFERENCES brain_findings_old(finding_id) ON DELETE SET NULL
94
+ );
95
+
96
+ INSERT INTO brain_findings_old (
97
+ finding_id, run_id, cycle_key, detected_at, finding_type, schema_version,
98
+ scope_type, scope_key, program_key, title, summary, why_now, evidence_hash,
99
+ involved_projects_json, suggested_artifact, owner_hint_json,
100
+ closure_condition_kind, closure_condition_json, closure_condition_human,
101
+ severity, confidence, approval_state, regression_of_finding_id,
102
+ proposal_fingerprint, recurrence_count, first_seen_cycle_key,
103
+ last_seen_cycle_key, applied_artifact_ref, applied_at, applied_by_user_id,
104
+ expires_at, superseded_by_finding_id, created_at, updated_at
105
+ )
106
+ SELECT
107
+ finding_id, run_id, cycle_key, detected_at, finding_type, schema_version,
108
+ scope_type, scope_key, program_key, title, summary, why_now, evidence_hash,
109
+ involved_projects_json, suggested_artifact, owner_hint_json,
110
+ closure_condition_kind, closure_condition_json, closure_condition_human,
111
+ severity, confidence, approval_state, regression_of_finding_id,
112
+ proposal_fingerprint, recurrence_count, first_seen_cycle_key,
113
+ last_seen_cycle_key, applied_artifact_ref, applied_at, applied_by_user_id,
114
+ expires_at, superseded_by_finding_id, created_at, updated_at
115
+ FROM brain_findings;
116
+
117
+ DROP TABLE brain_findings;
118
+ ALTER TABLE brain_findings_old RENAME TO brain_findings;
119
+
120
+ CREATE UNIQUE INDEX uk_brain_findings_natural
121
+ ON brain_findings(cycle_key, finding_type, scope_type, scope_key, evidence_hash, closure_condition_kind);
122
+ CREATE INDEX idx_brain_findings_scope_cycle
123
+ ON brain_findings(scope_type, scope_key, cycle_key DESC) WHERE superseded_by_finding_id IS NULL;
124
+ CREATE INDEX idx_brain_findings_open
125
+ ON brain_findings(approval_state, created_at DESC) WHERE approval_state = 'open';
126
+ CREATE INDEX idx_brain_findings_fingerprint
127
+ ON brain_findings(proposal_fingerprint, cycle_key DESC);
128
+ CREATE INDEX idx_brain_findings_type_cycle
129
+ ON brain_findings(finding_type, cycle_key DESC);
130
+ CREATE INDEX idx_brain_findings_run
131
+ ON brain_findings(run_id);
132
+ CREATE INDEX idx_brain_findings_regression
133
+ ON brain_findings(regression_of_finding_id) WHERE regression_of_finding_id IS NOT NULL;
134
+
135
+ CREATE TRIGGER trg_brain_findings_updated_at
136
+ AFTER UPDATE ON brain_findings FOR EACH ROW WHEN NEW.updated_at = OLD.updated_at
137
+ BEGIN
138
+ UPDATE brain_findings SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ','now') WHERE finding_id = NEW.finding_id;
139
+ END;
140
+ CREATE TRIGGER trg_brain_findings_no_delete_resolved
141
+ BEFORE DELETE ON brain_findings FOR EACH ROW WHEN OLD.approval_state = 'resolved'
142
+ BEGIN
143
+ SELECT RAISE(ABORT, 'cannot delete resolved finding');
144
+ END;
145
+ CREATE TRIGGER trg_brain_findings_terminal_forward_only
146
+ BEFORE UPDATE OF approval_state ON brain_findings FOR EACH ROW
147
+ WHEN OLD.approval_state IN ('dismissed','resolved','expired') AND NEW.approval_state <> OLD.approval_state
148
+ BEGIN
149
+ SELECT RAISE(ABORT, 'terminal finding state is forward-only');
150
+ END;
151
+
152
+ -- =============================================================================
153
+ -- 2b. Revert brain_finding_states to_state CHECK
154
+ -- =============================================================================
155
+
156
+ DELETE FROM brain_finding_states WHERE to_state IN ('pending_bootstrap', 'applied');
157
+
158
+ DROP INDEX IF EXISTS idx_brain_findings_states_finding;
159
+ DROP INDEX IF EXISTS idx_brain_findings_states_actor;
160
+
161
+ CREATE TABLE brain_finding_states_old (
162
+ state_id TEXT PRIMARY KEY,
163
+ finding_id TEXT NOT NULL,
164
+ from_state TEXT,
165
+ to_state TEXT NOT NULL
166
+ CHECK(to_state IN ('open','approved','dismissed','resolved','superseded','expired')),
167
+ actor_user_id TEXT,
168
+ reason TEXT CHECK(reason IS NULL OR length(reason) <= 500),
169
+ applied_artifact_ref TEXT,
170
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
171
+ FOREIGN KEY (finding_id) REFERENCES brain_findings(finding_id) ON DELETE RESTRICT
172
+ );
173
+
174
+ INSERT INTO brain_finding_states_old SELECT * FROM brain_finding_states;
175
+ DROP TABLE brain_finding_states;
176
+ ALTER TABLE brain_finding_states_old RENAME TO brain_finding_states;
177
+
178
+ CREATE INDEX idx_brain_findings_states_finding ON brain_finding_states(finding_id, created_at DESC);
179
+ CREATE INDEX idx_brain_findings_states_actor ON brain_finding_states(actor_user_id, created_at DESC);
180
+
181
+ -- =============================================================================
182
+ -- 3. Revert brain_drift_signals (remove DR8 + direction_misalignment)
183
+ -- =============================================================================
184
+
185
+ DELETE FROM brain_drift_signals
186
+ WHERE rule_id = 'DR8' OR signal_type = 'direction_misalignment';
187
+
188
+ DROP TRIGGER IF EXISTS trg_brain_drift_signals_updated_at;
189
+ DROP INDEX IF EXISTS idx_brain_drift_signals_scope_cycle;
190
+ DROP INDEX IF EXISTS idx_brain_drift_signals_scope_type;
191
+ DROP INDEX IF EXISTS idx_brain_drift_signals_type_cycle;
192
+ DROP INDEX IF EXISTS idx_brain_drift_signals_observed_ref;
193
+ DROP INDEX IF EXISTS idx_brain_drift_signals_run;
194
+ DROP INDEX IF EXISTS idx_brain_drift_signals_recurrence;
195
+ DROP INDEX IF EXISTS idx_brain_drift_signals_open_severity;
196
+ DROP INDEX IF EXISTS idx_brain_drift_signals_lookback;
197
+ DROP INDEX IF EXISTS idx_brain_drift_signals_axis;
198
+
199
+ CREATE TABLE brain_drift_signals_old (
200
+ signal_id TEXT PRIMARY KEY,
201
+ run_id TEXT NOT NULL,
202
+ cycle_key TEXT NOT NULL,
203
+ detected_at TEXT NOT NULL CHECK(detected_at LIKE '%Z' OR detected_at LIKE '%+00:00'),
204
+ rule_id TEXT NOT NULL CHECK(rule_id IN ('DR1','DR2','DR3','DR4','DR5','DR6','DR7')),
205
+ schema_version INTEGER NOT NULL DEFAULT 1,
206
+ scope_type TEXT NOT NULL CHECK(scope_type IN ('company','program','project')),
207
+ scope_key TEXT NOT NULL,
208
+ program_key TEXT,
209
+ signal_type TEXT NOT NULL
210
+ CHECK(signal_type IN (
211
+ 'activity_without_status','decision_without_adr','playbook_changed',
212
+ 'stale_open_loop','docs_governance_drift','external_update_unpropagated',
213
+ 'claimed_decision_gap'
214
+ )),
215
+ knowledge_form TEXT NOT NULL
216
+ CHECK(knowledge_form IN ('adr','spec','playbook','tribal_memory','external_update','claimed_decision','unknown')),
217
+ classifier_version INTEGER NOT NULL DEFAULT 1,
218
+ expected_direction_source TEXT NOT NULL
219
+ CHECK(expected_direction_source IN (
220
+ 'journal','project_status','handoff','doc','brainstorm','meeting_transcript','none','task','pr','commit'
221
+ )),
222
+ expected_direction_ref TEXT,
223
+ observed_direction_ref TEXT NOT NULL,
224
+ observed_delta TEXT NOT NULL CHECK(length(observed_delta) <= 2000),
225
+ evidence_json TEXT NOT NULL DEFAULT '[]' CHECK(json_valid(evidence_json)),
226
+ evidence_hash TEXT NOT NULL CHECK(length(evidence_hash) = 64),
227
+ severity TEXT NOT NULL CHECK(severity IN ('low','medium','high','critical')),
228
+ confidence REAL NOT NULL CHECK(confidence BETWEEN 0.0 AND 1.0 AND confidence = confidence),
229
+ recurrence_key TEXT NOT NULL,
230
+ involved_projects_json TEXT NOT NULL DEFAULT '[]' CHECK(json_valid(involved_projects_json)),
231
+ state TEXT NOT NULL DEFAULT 'open' CHECK(state IN ('open','superseded','resolved','dismissed')),
232
+ superseded_by_signal_id TEXT,
233
+ resolved_at TEXT,
234
+ dismissed_at TEXT,
235
+ dismissed_by TEXT,
236
+ dismiss_reason TEXT,
237
+ drift_axis TEXT CHECK(drift_axis IS NULL OR drift_axis IN ('intent','context','both')),
238
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
239
+ updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
240
+ FOREIGN KEY (run_id) REFERENCES brain_runs(run_id) ON DELETE RESTRICT,
241
+ FOREIGN KEY (superseded_by_signal_id) REFERENCES brain_drift_signals_old(signal_id)
242
+ );
243
+
244
+ INSERT INTO brain_drift_signals_old SELECT * FROM brain_drift_signals;
245
+ DROP TABLE brain_drift_signals;
246
+ ALTER TABLE brain_drift_signals_old RENAME TO brain_drift_signals;
247
+
248
+ CREATE INDEX idx_brain_drift_signals_scope_cycle ON brain_drift_signals(scope_type, scope_key, cycle_key DESC);
249
+ CREATE INDEX idx_brain_drift_signals_scope_type ON brain_drift_signals(scope_type, scope_key, cycle_key DESC, signal_type);
250
+ CREATE INDEX idx_brain_drift_signals_type_cycle ON brain_drift_signals(signal_type, cycle_key DESC);
251
+ CREATE INDEX idx_brain_drift_signals_observed_ref ON brain_drift_signals(observed_direction_ref, signal_type, cycle_key DESC);
252
+ CREATE INDEX idx_brain_drift_signals_run ON brain_drift_signals(run_id);
253
+ CREATE INDEX idx_brain_drift_signals_recurrence ON brain_drift_signals(recurrence_key, cycle_key DESC);
254
+ CREATE INDEX idx_brain_drift_signals_open_severity ON brain_drift_signals(severity, cycle_key DESC)
255
+ WHERE state = 'open' AND superseded_by_signal_id IS NULL;
256
+ CREATE INDEX idx_brain_drift_signals_lookback ON brain_drift_signals(scope_type, scope_key, signal_type, resolved_at)
257
+ WHERE resolved_at IS NULL AND state = 'open';
258
+ CREATE INDEX idx_brain_drift_signals_axis ON brain_drift_signals(cycle_key, drift_axis) WHERE drift_axis IS NOT NULL;
259
+
260
+ CREATE TRIGGER trg_brain_drift_signals_updated_at
261
+ AFTER UPDATE ON brain_drift_signals FOR EACH ROW WHEN NEW.updated_at = OLD.updated_at
262
+ BEGIN
263
+ UPDATE brain_drift_signals SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ','now') WHERE signal_id = NEW.signal_id;
264
+ END;
265
+
266
+ -- =============================================================================
267
+ -- 4. Remove schema_versions entry
268
+ -- =============================================================================
269
+ DELETE FROM schema_versions WHERE version = 133;
270
+
271
+ COMMIT;
272
+
273
+ PRAGMA foreign_keys = ON;
@@ -0,0 +1,8 @@
1
+ -- Wave 3.1 Gap 2: persist LLM-polished narrative on journal entries.
2
+ -- Polished after cycle publish when settings.brain_llm_polish_enabled=1
3
+ -- and the entry is non-empty (is_empty=0). NULL when polish disabled or LLM
4
+ -- unavailable; deterministic body_json always present as fallback.
5
+
6
+ ALTER TABLE brain_journal_entries ADD COLUMN narrative_polished TEXT;
7
+ ALTER TABLE brain_journal_entries ADD COLUMN narrative_polished_at TEXT;
8
+ ALTER TABLE brain_journal_entries ADD COLUMN narrative_polished_model TEXT;
@@ -0,0 +1,6 @@
1
+ -- Down migration: drop narrative_polished columns. SQLite ALTER TABLE DROP
2
+ -- COLUMN requires 3.35+; the runtime is 3.45+ so we use it directly.
3
+
4
+ ALTER TABLE brain_journal_entries DROP COLUMN narrative_polished_model;
5
+ ALTER TABLE brain_journal_entries DROP COLUMN narrative_polished_at;
6
+ ALTER TABLE brain_journal_entries DROP COLUMN narrative_polished;
@@ -0,0 +1,21 @@
1
+ -- Migration 135 — KG edge provider tracking
2
+ --
3
+ -- Adds a nullable provider field for newly written KG edges. The live KG edge
4
+ -- table is named `graph_edges`; this migration keeps the task wording
5
+ -- `kg_edges_provider` in the filename for traceability.
6
+ --
7
+ -- No retroactive backfill is performed in this migration. Legacy `similar_to`
8
+ -- rows stay NULL until they are naturally recomputed by the populator during
9
+ -- the transition window.
10
+ --
11
+ -- Idempotency note:
12
+ -- SQLite does not support `ALTER TABLE ... ADD COLUMN IF NOT EXISTS`. The
13
+ -- guarded column add and index creation run in the version-135 post-migration
14
+ -- hook in `core/api/db.py`. This SQL file only reserves/stamps the version so
15
+ -- startup migration ordering remains deterministic.
16
+
17
+ BEGIN IMMEDIATE;
18
+
19
+ INSERT OR IGNORE INTO schema_versions(version) VALUES (135);
20
+
21
+ COMMIT;
@@ -0,0 +1,56 @@
1
+ -- Migration 136 — documents_fts for W2 hybrid retrieval
2
+ --
3
+ -- Adds an FTS5 index over the semantic-search documents table so
4
+ -- embedding_service.search_by_type can fuse sqlite-vec KNN with BM25 over
5
+ -- handoffs, files, audits, learnings, tasks, inbox items, and projects.
6
+ --
7
+ -- We intentionally keep the FTS table content-owned instead of
8
+ -- content='documents': the live documents table has doc_title/file_path but
9
+ -- no title/content body columns, and an external-content FTS5 table with
10
+ -- non-existent source columns breaks ordinary reads and rebuilds. The Python
11
+ -- migration post-hook backfills full file/row bodies where possible.
12
+
13
+ BEGIN IMMEDIATE;
14
+
15
+ CREATE VIRTUAL TABLE IF NOT EXISTS documents_fts USING fts5(
16
+ doc_id UNINDEXED,
17
+ title,
18
+ content,
19
+ tokenize='porter unicode61 remove_diacritics 2'
20
+ );
21
+
22
+ -- SQL-only fallback backfill. The migration runner post-hook replaces these
23
+ -- lightweight rows with full readable body text for loadable documents.
24
+ INSERT INTO documents_fts(rowid, doc_id, title, content)
25
+ SELECT d.id, d.id, d.file_path, d.file_path
26
+ FROM documents AS d
27
+ WHERE NOT EXISTS (
28
+ SELECT 1
29
+ FROM documents_fts AS f
30
+ WHERE f.rowid = d.id
31
+ );
32
+
33
+ DROP TRIGGER IF EXISTS documents_fts_insert;
34
+ CREATE TRIGGER documents_fts_insert AFTER INSERT ON documents
35
+ BEGIN
36
+ INSERT INTO documents_fts(rowid, doc_id, title, content)
37
+ VALUES (NEW.id, NEW.id, NEW.file_path, NEW.file_path);
38
+ END;
39
+
40
+ DROP TRIGGER IF EXISTS documents_fts_update;
41
+ CREATE TRIGGER documents_fts_update AFTER UPDATE ON documents
42
+ BEGIN
43
+ DELETE FROM documents_fts WHERE rowid = OLD.id;
44
+ INSERT INTO documents_fts(rowid, doc_id, title, content)
45
+ VALUES (NEW.id, NEW.id, NEW.file_path, NEW.file_path);
46
+ END;
47
+
48
+ DROP TRIGGER IF EXISTS documents_fts_delete;
49
+ CREATE TRIGGER documents_fts_delete AFTER DELETE ON documents
50
+ BEGIN
51
+ DELETE FROM documents_fts WHERE rowid = OLD.id;
52
+ END;
53
+
54
+ COMMIT;
55
+
56
+ INSERT OR IGNORE INTO schema_versions (version) VALUES (136);
@@ -0,0 +1,59 @@
1
+ -- v1.0.0 - 2026-04-30 - Promote llm_costs from lazy-create to formal migration
2
+ --
3
+ -- Until now `llm_costs` was lazy-created by inbox_llm_classifier._ensure_llm_costs_table().
4
+ -- That helper shipped the table only after the classifier path had been exercised at
5
+ -- least once, leaving fresh DB bootstrap + integration tests + Triage onboarding
6
+ -- without the table. Promote to a formal migration so every environment has the
7
+ -- schema from boot.
8
+ --
9
+ -- The schema preserves the existing column types already in production rows
10
+ -- (id TEXT, created_at TEXT ISO8601). Three new nullable columns are added for
11
+ -- MAC-Phase 0.5 LiteLLM gateway:
12
+ --
13
+ -- - tier_logical TEXT : logical model name (tier-think|tier-fast|...) or NULL for legacy.
14
+ -- - fallback_used INTEGER : 0/1 flag, set when LiteLLM falls back from local Mac to cloud.
15
+ -- - litellm_request_id TEXT : LiteLLM correlation id, for cross-DB debug
16
+ -- (Hetzner llm_costs ↔ Mac LiteLLM_SpendLogs).
17
+ --
18
+ -- WARNING: NEVER add prompt or response columns to llm_costs. PII / GDPR Art. 32
19
+ -- violation. Plain-text prompts/responses must live only in rotated file logs
20
+ -- with pii_redactor applied (retention <= 7 days, chmod 600).
21
+ --
22
+ -- Idempotency strategy:
23
+ -- - This SQL file does the safe-on-rerun parts (CREATE TABLE IF NOT EXISTS,
24
+ -- CREATE INDEX IF NOT EXISTS, schema_versions stamp).
25
+ -- - The post-migration Python hook `_promote_llm_costs_columns()` in api/db.py
26
+ -- handles ALTER TABLE ADD COLUMN for the 3 new columns, guarded by
27
+ -- `_column_exists()` so it is safe on both fresh DBs (where CREATE already
28
+ -- installed them) and prod DBs (where the lazy-created old schema lacked them).
29
+ --
30
+ -- DEPLOY PROCEDURE (auto via run_migrations at startup):
31
+ -- 1. Deploy api → /data/pir/migrations/137_promote_llm_costs.sql in place.
32
+ -- 2. systemctl --user restart pir-api.service.
33
+ -- 3. run_migrations() applies version 137, then runs the post-hook.
34
+ --
35
+ -- Reversible: vedi migrations/137_promote_llm_costs_down.sql (no-op, SQLite
36
+ -- pre-3.35 cannot DROP COLUMN; documented).
37
+
38
+ BEGIN IMMEDIATE;
39
+
40
+ CREATE TABLE IF NOT EXISTS llm_costs (
41
+ id TEXT PRIMARY KEY,
42
+ feature TEXT NOT NULL,
43
+ model TEXT,
44
+ input_tokens INTEGER,
45
+ output_tokens INTEGER,
46
+ cost_usd REAL NOT NULL,
47
+ workspace_id TEXT NOT NULL DEFAULT 'ws_default',
48
+ created_at TEXT DEFAULT (datetime('now','utc')),
49
+ tier_logical TEXT,
50
+ fallback_used INTEGER NOT NULL DEFAULT 0,
51
+ litellm_request_id TEXT
52
+ );
53
+
54
+ CREATE INDEX IF NOT EXISTS idx_llm_costs_feature_created
55
+ ON llm_costs(feature, created_at, workspace_id);
56
+
57
+ INSERT OR IGNORE INTO schema_versions (version) VALUES (137);
58
+
59
+ COMMIT;
@@ -0,0 +1,19 @@
1
+ -- Rollback per migration 137 (promote llm_costs).
2
+ --
3
+ -- SQLite pre-3.35 non supporta DROP COLUMN; per rollback canonico delle 3
4
+ -- nuove colonne (tier_logical, fallback_used, litellm_request_id) servirebbe
5
+ -- drop+recreate della tabella. Pero' llm_costs contiene dati operativi
6
+ -- (cost tracking inbox classifier, ~1500 row/mese) e ricrearla rischierebbe
7
+ -- perdita di dati. Per rollback al volo, basta rimuovere il version bump:
8
+ -- le colonne extra restano fisicamente in tabella ma il codice pre-137
9
+ -- semplicemente non le legge ne' scrive (NULL default).
10
+ --
11
+ -- Per rollback completo (drop colonne + ripristino lazy-create), servirebbe
12
+ -- una migration successiva con CREATE TABLE _new + INSERT SELECT + DROP +
13
+ -- RENAME. Non lo facciamo qui — questa down-migration e' "version bump only".
14
+
15
+ BEGIN IMMEDIATE;
16
+
17
+ DELETE FROM schema_versions WHERE version = 137;
18
+
19
+ COMMIT;
@@ -0,0 +1,39 @@
1
+ -- Migration 138: ingestion API-key credential (single-org).
2
+ -- v1.0.0 - 2026-05-26 - M1 CAPTURE U1
3
+ --
4
+ -- Purpose-built credential for the governed ingestion ingress (POST /api/v1/ingest).
5
+ -- NOT an extension of agent_tokens: agent_tokens is load-bearing for the 91-tool
6
+ -- MCP server; a separate table reuses the crypto (SHA-256 hash via security.py)
7
+ -- while isolating the per-source policy (no blast radius on MCP auth).
8
+ --
9
+ -- Convergence with agent_tokens (future M7 merge): same hashing helper,
10
+ -- same revoke-audit shape (revoked_at/by/reason), same expires_at semantics.
11
+ --
12
+ -- Rollback: migrations/138_ingest_api_keys_down.sql
13
+
14
+ CREATE TABLE IF NOT EXISTS ingest_api_keys (
15
+ id TEXT PRIMARY KEY, -- uuid
16
+ name TEXT NOT NULL, -- human label
17
+ token_hash TEXT NOT NULL UNIQUE, -- SHA-256 hex (reuse security.py _hash_token)
18
+ prefix TEXT NOT NULL, -- first chars for display (ing_xxxx...)
19
+ project_scope TEXT NOT NULL DEFAULT '[]', -- JSON array of slugs (default-deny)
20
+ ingest_policy TEXT NOT NULL DEFAULT 'open'
21
+ CHECK(ingest_policy IN ('open', 'trusted')),
22
+ default_source TEXT, -- label applied when payload omits source
23
+ rate_limit_per_min INTEGER NOT NULL DEFAULT 60,
24
+ daily_quota INTEGER NOT NULL DEFAULT 1000, -- durable abuse backstop (non-NULL by design)
25
+ workspace_id TEXT NOT NULL DEFAULT 'ws_default',
26
+ created_by TEXT, -- user slug who minted it
27
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
28
+ expires_at TEXT, -- NULL = no expiry
29
+ last_used_at TEXT,
30
+ is_active INTEGER NOT NULL DEFAULT 1,
31
+ revoked_at TEXT,
32
+ revoked_by TEXT,
33
+ revoke_reason TEXT
34
+ );
35
+
36
+ CREATE INDEX IF NOT EXISTS idx_ingest_api_keys_hash ON ingest_api_keys(token_hash);
37
+ CREATE INDEX IF NOT EXISTS idx_ingest_api_keys_active ON ingest_api_keys(is_active, workspace_id);
38
+
39
+ INSERT OR IGNORE INTO schema_versions(version) VALUES (138);
@@ -0,0 +1,8 @@
1
+ -- Rollback migration 138: drop ingest_api_keys.
2
+ -- v1.0.0 - 2026-05-26 - M1 CAPTURE U1
3
+
4
+ DROP INDEX IF EXISTS idx_ingest_api_keys_active;
5
+ DROP INDEX IF EXISTS idx_ingest_api_keys_hash;
6
+ DROP TABLE IF EXISTS ingest_api_keys;
7
+
8
+ DELETE FROM schema_versions WHERE version = 138;
@@ -0,0 +1,91 @@
1
+ -- Migration 139: ingress columns + 'api_ingress' source kind on ingest_pending.
2
+ -- v1.0.0 - 2026-05-26 - M1 CAPTURE U2
3
+ --
4
+ -- SQLite cannot alter a CHECK constraint in place, so ingest_pending is rebuilt
5
+ -- (same pattern as mig 126). Three governance columns are added in the same
6
+ -- rebuild (api_key_id, source, ingest_policy) — declared in the new-table DDL,
7
+ -- NOT via separate ALTER ADD COLUMN (a CHECK change forces a full rebuild, so a
8
+ -- standalone ALTER would be dead/conflicting). The ~324 historical rows keep
9
+ -- these columns NULL (owner drops, no API key) — correct, no backfill needed.
10
+ --
11
+ -- api_key_id is bare TEXT by design (no FK): key revocation is a soft-delete
12
+ -- (ingest_api_keys.revoked_at, never a row DELETE), so no dangling reference can
13
+ -- ever occur and no ON DELETE rule is required.
14
+ --
15
+ -- The PRAGMA foreign_keys=OFF envelope (mirrors mig 126) is mandatory: without
16
+ -- it, DROP TABLE ingest_pending cascade-deletes ingest_change_history (FK
17
+ -- ON DELETE CASCADE, mig 097 — the triage audit trail) and NULLs
18
+ -- ingest_skipped.existing_ingest_id (FK, mig 103). Invariant: row counts of
19
+ -- ingest_change_history / ingest_skipped are unchanged across this migration.
20
+ --
21
+ -- Rollback: migrations/139_ingest_pending_ingress_down.sql
22
+
23
+ PRAGMA foreign_keys=OFF;
24
+
25
+ BEGIN IMMEDIATE;
26
+
27
+ CREATE TABLE ingest_pending_new_139 (
28
+ id TEXT PRIMARY KEY,
29
+ file_path TEXT NOT NULL,
30
+ sha256 TEXT NOT NULL,
31
+ project_slug TEXT NOT NULL DEFAULT 'unclassified',
32
+ source_kind TEXT NOT NULL DEFAULT 'file_drop' CHECK(source_kind IN (
33
+ 'file_drop', 'manual_upload', 'api_upload', 'terminal_upload', 'api_ingress'
34
+ )),
35
+ mime_type TEXT,
36
+ file_size_bytes INTEGER,
37
+ parser_used TEXT,
38
+ extracted_text TEXT,
39
+ structure_json TEXT,
40
+ classification_json TEXT,
41
+ status TEXT NOT NULL DEFAULT 'queued' CHECK(status IN (
42
+ 'queued', 'parser_waiting', 'parsing', 'classified', 'awaiting_triage',
43
+ 'approved', 'inserted', 'done', 'parse_error', 'rejected'
44
+ )),
45
+ error_message TEXT,
46
+ triage_decision_id TEXT,
47
+ target_folder TEXT,
48
+ target_filename TEXT,
49
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
50
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
51
+ recovery_attempts INTEGER NOT NULL DEFAULT 0,
52
+ locked_by TEXT,
53
+ locked_at TEXT,
54
+ -- M1 CAPTURE ingress columns (NULL for owner drops):
55
+ api_key_id TEXT, -- ingest_api_keys.id (bare TEXT, soft-delete keys → no dangling ref)
56
+ source TEXT, -- payload source label (provenance / filtering)
57
+ ingest_policy TEXT, -- snapshot of key policy at intake ('open' | 'trusted')
58
+ UNIQUE(sha256, project_slug)
59
+ );
60
+
61
+ INSERT INTO ingest_pending_new_139 (
62
+ id, file_path, sha256, project_slug, source_kind, mime_type,
63
+ file_size_bytes, parser_used, extracted_text, structure_json,
64
+ classification_json, status, error_message, triage_decision_id,
65
+ target_folder, target_filename, created_at, updated_at,
66
+ recovery_attempts, locked_by, locked_at
67
+ )
68
+ SELECT
69
+ id, file_path, sha256, project_slug, source_kind, mime_type,
70
+ file_size_bytes, parser_used, extracted_text, structure_json,
71
+ classification_json, status, error_message, triage_decision_id,
72
+ target_folder, target_filename, created_at, updated_at,
73
+ recovery_attempts, locked_by, locked_at
74
+ FROM ingest_pending;
75
+
76
+ DROP TABLE ingest_pending;
77
+ ALTER TABLE ingest_pending_new_139 RENAME TO ingest_pending;
78
+
79
+ CREATE INDEX idx_ingest_pending_status ON ingest_pending(status);
80
+ CREATE INDEX idx_ingest_pending_project ON ingest_pending(project_slug);
81
+ CREATE INDEX idx_ingest_pending_created ON ingest_pending(created_at DESC);
82
+ CREATE INDEX idx_ingest_pending_lock ON ingest_pending(locked_at)
83
+ WHERE locked_at IS NOT NULL;
84
+ CREATE INDEX idx_ingest_pending_source ON ingest_pending(source);
85
+ CREATE INDEX idx_ingest_pending_api_key ON ingest_pending(api_key_id);
86
+
87
+ INSERT OR IGNORE INTO schema_versions(version) VALUES (139);
88
+
89
+ COMMIT;
90
+
91
+ PRAGMA foreign_keys=ON;
@@ -0,0 +1,73 @@
1
+ -- Rollback migration 139: drop ingress columns + 'api_ingress' source kind.
2
+ -- v1.0.0 - 2026-05-26 - M1 CAPTURE U2
3
+ --
4
+ -- SQLite cannot drop a CHECK value in place, so this is a reverse full rebuild
5
+ -- back to the pre-139 (mig 126) DDL. Any 'api_ingress' rows are first demoted to
6
+ -- 'file_drop' so they survive the restored CHECK. Same foreign_keys=OFF envelope
7
+ -- as the up migration (protects ingest_change_history / ingest_skipped FKs).
8
+
9
+ PRAGMA foreign_keys=OFF;
10
+
11
+ BEGIN IMMEDIATE;
12
+
13
+ UPDATE ingest_pending SET source_kind = 'file_drop' WHERE source_kind = 'api_ingress';
14
+
15
+ CREATE TABLE ingest_pending_old_139 (
16
+ id TEXT PRIMARY KEY,
17
+ file_path TEXT NOT NULL,
18
+ sha256 TEXT NOT NULL,
19
+ project_slug TEXT NOT NULL DEFAULT 'unclassified',
20
+ source_kind TEXT NOT NULL DEFAULT 'file_drop' CHECK(source_kind IN (
21
+ 'file_drop', 'manual_upload', 'api_upload', 'terminal_upload'
22
+ )),
23
+ mime_type TEXT,
24
+ file_size_bytes INTEGER,
25
+ parser_used TEXT,
26
+ extracted_text TEXT,
27
+ structure_json TEXT,
28
+ classification_json TEXT,
29
+ status TEXT NOT NULL DEFAULT 'queued' CHECK(status IN (
30
+ 'queued', 'parser_waiting', 'parsing', 'classified', 'awaiting_triage',
31
+ 'approved', 'inserted', 'done', 'parse_error', 'rejected'
32
+ )),
33
+ error_message TEXT,
34
+ triage_decision_id TEXT,
35
+ target_folder TEXT,
36
+ target_filename TEXT,
37
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
38
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
39
+ recovery_attempts INTEGER NOT NULL DEFAULT 0,
40
+ locked_by TEXT,
41
+ locked_at TEXT,
42
+ UNIQUE(sha256, project_slug)
43
+ );
44
+
45
+ INSERT INTO ingest_pending_old_139 (
46
+ id, file_path, sha256, project_slug, source_kind, mime_type,
47
+ file_size_bytes, parser_used, extracted_text, structure_json,
48
+ classification_json, status, error_message, triage_decision_id,
49
+ target_folder, target_filename, created_at, updated_at,
50
+ recovery_attempts, locked_by, locked_at
51
+ )
52
+ SELECT
53
+ id, file_path, sha256, project_slug, source_kind, mime_type,
54
+ file_size_bytes, parser_used, extracted_text, structure_json,
55
+ classification_json, status, error_message, triage_decision_id,
56
+ target_folder, target_filename, created_at, updated_at,
57
+ recovery_attempts, locked_by, locked_at
58
+ FROM ingest_pending;
59
+
60
+ DROP TABLE ingest_pending;
61
+ ALTER TABLE ingest_pending_old_139 RENAME TO ingest_pending;
62
+
63
+ CREATE INDEX idx_ingest_pending_status ON ingest_pending(status);
64
+ CREATE INDEX idx_ingest_pending_project ON ingest_pending(project_slug);
65
+ CREATE INDEX idx_ingest_pending_created ON ingest_pending(created_at DESC);
66
+ CREATE INDEX idx_ingest_pending_lock ON ingest_pending(locked_at)
67
+ WHERE locked_at IS NOT NULL;
68
+
69
+ DELETE FROM schema_versions WHERE version = 139;
70
+
71
+ COMMIT;
72
+
73
+ PRAGMA foreign_keys=ON;