@straiffi/archon 1.10.1 → 1.10.2

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 (170) hide show
  1. package/dist/client/assets/ActivityView-CdDT5tgr.js +1 -0
  2. package/dist/client/assets/{GitHubActionsDialog-BABPYwJP.js → GitHubActionsDialog-NdYtgMhg.js} +1 -1
  3. package/dist/client/assets/{VerificationDialog-LN87YY0r.js → VerificationDialog-BfIKtVjt.js} +1 -1
  4. package/dist/client/assets/{architectureDiagram-3BPJPVTR-DBXhcjPI.js → architectureDiagram-3BPJPVTR-C4zoWnXM.js} +1 -1
  5. package/dist/client/assets/{blockDiagram-GPEHLZMM-c3auwNH7.js → blockDiagram-GPEHLZMM-ZhRwV8ma.js} +1 -1
  6. package/dist/client/assets/{c4Diagram-AAUBKEIU-DH2YznEQ.js → c4Diagram-AAUBKEIU-CA2USxCJ.js} +1 -1
  7. package/dist/client/assets/channel-C4I-VlJu.js +1 -0
  8. package/dist/client/assets/{chunk-2J33WTMH-D0_MoyXZ.js → chunk-2J33WTMH-CY32Brnt.js} +1 -1
  9. package/dist/client/assets/{chunk-3OPIFGDE-DLvSp1DN.js → chunk-3OPIFGDE-H70UH7rH.js} +1 -1
  10. package/dist/client/assets/{chunk-5ZQYHXKU-B4sX8Htk.js → chunk-5ZQYHXKU-DC1dllSt.js} +1 -1
  11. package/dist/client/assets/{chunk-727SXJPM-CkdnShG1.js → chunk-727SXJPM-DVIgI7hM.js} +1 -1
  12. package/dist/client/assets/{chunk-AQP2D5EJ-BdPfgkcs.js → chunk-AQP2D5EJ-gwSYEPou.js} +1 -1
  13. package/dist/client/assets/{chunk-CSCIHK7Q-CK-DpVF6.js → chunk-CSCIHK7Q-Z1cfABPc.js} +1 -1
  14. package/dist/client/assets/{chunk-KSCS5N6A-DSbTWVl2.js → chunk-KSCS5N6A-DFoW6dtq.js} +1 -1
  15. package/dist/client/assets/{chunk-L5ZTLDWV-DuQ4EPLl.js → chunk-L5ZTLDWV-CmQbbP8b.js} +1 -1
  16. package/dist/client/assets/{chunk-LZXEDZCA-CtpoXWMY.js → chunk-LZXEDZCA-Ba16nX-R.js} +2 -2
  17. package/dist/client/assets/{chunk-ND2GUHAM-CDfNOP6o.js → chunk-ND2GUHAM-Bc7u1Zqm.js} +1 -1
  18. package/dist/client/assets/{chunk-NZK2D7GU-s6ReY4ev.js → chunk-NZK2D7GU-DNXYx7JX.js} +1 -1
  19. package/dist/client/assets/{chunk-O5CBEL6O-DxqYGKhS.js → chunk-O5CBEL6O-Ba00cuZ5.js} +1 -1
  20. package/dist/client/assets/{chunk-WU5MYG2G-BvrhxyV8.js → chunk-WU5MYG2G-SJ_ny5dU.js} +1 -1
  21. package/dist/client/assets/classDiagram-4FO5ZUOK-Ca3KxBnW.js +1 -0
  22. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-CSpMessw.js +1 -0
  23. package/dist/client/assets/{dagre-BM42HDAG-DEK_rftr.js → dagre-BM42HDAG-CL2dKbj9.js} +1 -1
  24. package/dist/client/assets/{diagram-2AECGRRQ-CpobcZnv.js → diagram-2AECGRRQ-DQq1qZ0l.js} +1 -1
  25. package/dist/client/assets/{diagram-5GNKFQAL-zL1D1L_8.js → diagram-5GNKFQAL-Zf0YQuRe.js} +1 -1
  26. package/dist/client/assets/{diagram-KO2AKTUF-gyW-Vc7c.js → diagram-KO2AKTUF-DcUxL9SG.js} +1 -1
  27. package/dist/client/assets/{diagram-LMA3HP47-DDEYc8sh.js → diagram-LMA3HP47-BAIixEu7.js} +1 -1
  28. package/dist/client/assets/{diagram-OG6HWLK6-BtUrfJnE.js → diagram-OG6HWLK6-Dhhjm84p.js} +1 -1
  29. package/dist/client/assets/{erDiagram-TEJ5UH35-qGrmpmmk.js → erDiagram-TEJ5UH35-BcQOacBP.js} +1 -1
  30. package/dist/client/assets/{flowDiagram-I6XJVG4X-DO1Nm1FA.js → flowDiagram-I6XJVG4X-BZIJqLp3.js} +1 -1
  31. package/dist/client/assets/{ganttDiagram-6RSMTGT7-DGuMVCAc.js → ganttDiagram-6RSMTGT7-DFC6qgrY.js} +1 -1
  32. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-CehPAc8-.js → gitGraphDiagram-PVQCEYII-Ds0nwSU0.js} +1 -1
  33. package/dist/client/assets/index-Bg3l17L3.css +2 -0
  34. package/dist/client/assets/index-D_KmViSu.js +276 -0
  35. package/dist/client/assets/{infoDiagram-5YYISTIA-BkRaMDId.js → infoDiagram-5YYISTIA-DfDrR5Mz.js} +1 -1
  36. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-B45ubODJ.js → ishikawaDiagram-YF4QCWOH-B2v4Byji.js} +1 -1
  37. package/dist/client/assets/{journeyDiagram-JHISSGLW-BLxrlitK.js → journeyDiagram-JHISSGLW-CO6laklO.js} +1 -1
  38. package/dist/client/assets/{kanban-definition-UN3LZRKU-DmyeJDyy.js → kanban-definition-UN3LZRKU-BziFO199.js} +1 -1
  39. package/dist/client/assets/{line-BhwjsX6t.js → line-Vb0A8-Oe.js} +1 -1
  40. package/dist/client/assets/{mermaid-parser.core-CPvivy_u.js → mermaid-parser.core-Bm3Xv0Zt.js} +1 -1
  41. package/dist/client/assets/{mermaid.core-Dr0kld-g.js → mermaid.core-DXBRp0XG.js} +3 -3
  42. package/dist/client/assets/{mindmap-definition-RKZ34NQL-dfudPzBR.js → mindmap-definition-RKZ34NQL-4GueJvPT.js} +1 -1
  43. package/dist/client/assets/{pieDiagram-4H26LBE5-BhsIQVNX.js → pieDiagram-4H26LBE5-Djy0sVJR.js} +1 -1
  44. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-CAKxScLD.js → quadrantDiagram-W4KKPZXB-3rWAi4K5.js} +1 -1
  45. package/dist/client/assets/{requirementDiagram-4Y6WPE33-Br6jIbke.js → requirementDiagram-4Y6WPE33-D7-WCnjH.js} +1 -1
  46. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-BqujNgnY.js → sankeyDiagram-5OEKKPKP-B4-3BUQ2.js} +1 -1
  47. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-Dr_VM_ei.js → sequenceDiagram-3UESZ5HK-DCWomuSc.js} +1 -1
  48. package/dist/client/assets/{stateDiagram-AJRCARHV-CDbSbbTW.js → stateDiagram-AJRCARHV-DpsWWFaO.js} +1 -1
  49. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-BE_IAuYt.js +1 -0
  50. package/dist/client/assets/{timeline-definition-PNZ67QCA-CnuLuWDs.js → timeline-definition-PNZ67QCA-B0Mh4MHF.js} +1 -1
  51. package/dist/client/assets/{vennDiagram-CIIHVFJN-CVAhxdBZ.js → vennDiagram-CIIHVFJN-Dpxr8LTG.js} +1 -1
  52. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-Dmczey27.js → wardleyDiagram-YWT4CUSO-BdAz5ERd.js} +1 -1
  53. package/dist/client/assets/{xychartDiagram-2RQKCTM6-Bl6JGLCU.js → xychartDiagram-2RQKCTM6-BV9Ah-jk.js} +1 -1
  54. package/dist/client/index.html +2 -2
  55. package/dist/server/db.js +640 -0
  56. package/dist/server/db.js.map +1 -1
  57. package/dist/server/index.js +787 -124
  58. package/dist/server/index.js.map +1 -1
  59. package/dist/server/lib/agentCatalog.js +35 -0
  60. package/dist/server/lib/agentCatalog.js.map +1 -0
  61. package/dist/server/lib/agentModelConfig.js +151 -0
  62. package/dist/server/lib/agentModelConfig.js.map +1 -0
  63. package/dist/server/lib/agentRuns.js +1 -0
  64. package/dist/server/lib/agentRuns.js.map +1 -1
  65. package/dist/server/lib/automationCheckGate.js +98 -9
  66. package/dist/server/lib/automationCheckGate.js.map +1 -1
  67. package/dist/server/lib/automationLoopAgentEvidence.js +42 -0
  68. package/dist/server/lib/automationLoopAgentEvidence.js.map +1 -0
  69. package/dist/server/lib/automationLoopProjection.js +339 -0
  70. package/dist/server/lib/automationLoopProjection.js.map +1 -0
  71. package/dist/server/lib/automationProgression.js +115 -6
  72. package/dist/server/lib/automationProgression.js.map +1 -1
  73. package/dist/server/lib/automationReconciliation.js +27 -11
  74. package/dist/server/lib/automationReconciliation.js.map +1 -1
  75. package/dist/server/lib/automationResumeDecision.js +55 -15
  76. package/dist/server/lib/automationResumeDecision.js.map +1 -1
  77. package/dist/server/lib/automationReviewGate.js +352 -26
  78. package/dist/server/lib/automationReviewGate.js.map +1 -1
  79. package/dist/server/lib/buildFlow.js +12 -0
  80. package/dist/server/lib/buildFlow.js.map +1 -1
  81. package/dist/server/lib/bundleReviewOperations.js +40 -23
  82. package/dist/server/lib/bundleReviewOperations.js.map +1 -1
  83. package/dist/server/lib/chatOperations.js +26 -4
  84. package/dist/server/lib/chatOperations.js.map +1 -1
  85. package/dist/server/lib/checkAutoFix.js +5 -4
  86. package/dist/server/lib/checkAutoFix.js.map +1 -1
  87. package/dist/server/lib/checkAutoFixDetails.js +54 -9
  88. package/dist/server/lib/checkAutoFixDetails.js.map +1 -1
  89. package/dist/server/lib/checkGateEvaluations.js +6 -1
  90. package/dist/server/lib/checkGateEvaluations.js.map +1 -1
  91. package/dist/server/lib/checkRepair.js +30 -0
  92. package/dist/server/lib/checkRepair.js.map +1 -1
  93. package/dist/server/lib/claudeAgentProvider.js +19 -0
  94. package/dist/server/lib/claudeAgentProvider.js.map +1 -1
  95. package/dist/server/lib/executionRuns.js +17 -3
  96. package/dist/server/lib/executionRuns.js.map +1 -1
  97. package/dist/server/lib/executionTimeline.js +3 -0
  98. package/dist/server/lib/executionTimeline.js.map +1 -1
  99. package/dist/server/lib/lightweightPrompt.js +13 -40
  100. package/dist/server/lib/lightweightPrompt.js.map +1 -1
  101. package/dist/server/lib/mobileAccess.js +47 -3
  102. package/dist/server/lib/mobileAccess.js.map +1 -1
  103. package/dist/server/lib/modelResolutionErrors.js +24 -0
  104. package/dist/server/lib/modelResolutionErrors.js.map +1 -0
  105. package/dist/server/lib/models.js +9 -9
  106. package/dist/server/lib/models.js.map +1 -1
  107. package/dist/server/lib/projectAutoConfig.js +15 -52
  108. package/dist/server/lib/projectAutoConfig.js.map +1 -1
  109. package/dist/server/lib/projectMemoryScan.js +15 -9
  110. package/dist/server/lib/projectMemoryScan.js.map +1 -1
  111. package/dist/server/lib/projects.js +59 -4
  112. package/dist/server/lib/projects.js.map +1 -1
  113. package/dist/server/lib/reviewRepairCompletion.js +126 -0
  114. package/dist/server/lib/reviewRepairCompletion.js.map +1 -0
  115. package/dist/server/lib/reviewRepairIterationRecords.js +149 -0
  116. package/dist/server/lib/reviewRepairIterationRecords.js.map +1 -0
  117. package/dist/server/lib/reviewRepairIterations.js +590 -0
  118. package/dist/server/lib/reviewRepairIterations.js.map +1 -0
  119. package/dist/server/lib/reviewRepairReconciliation.js +588 -0
  120. package/dist/server/lib/reviewRepairReconciliation.js.map +1 -0
  121. package/dist/server/lib/reviewerConfig.js +18 -7
  122. package/dist/server/lib/reviewerConfig.js.map +1 -1
  123. package/dist/server/lib/run.js +7 -2
  124. package/dist/server/lib/run.js.map +1 -1
  125. package/dist/server/lib/specArtifact.js +1 -1
  126. package/dist/server/lib/specArtifact.js.map +1 -1
  127. package/dist/server/lib/specGraphFeature.js +2 -2
  128. package/dist/server/lib/specGraphFeature.js.map +1 -1
  129. package/dist/server/lib/specOperations.js +26 -4
  130. package/dist/server/lib/specOperations.js.map +1 -1
  131. package/dist/server/lib/specRepositoryEvidenceFormatting.js +2 -2
  132. package/dist/server/lib/specRepositoryEvidenceFormatting.js.map +1 -1
  133. package/dist/server/lib/specRepositoryImpact.js +3 -3
  134. package/dist/server/lib/specRepositoryImpact.js.map +1 -1
  135. package/dist/server/lib/specReviewContext.js +7 -1
  136. package/dist/server/lib/specReviewContext.js.map +1 -1
  137. package/dist/server/lib/specReviewOperations.js +20 -7
  138. package/dist/server/lib/specReviewOperations.js.map +1 -1
  139. package/dist/server/lib/specSnapshotEvidence.js +3 -3
  140. package/dist/server/lib/specSnapshotEvidence.js.map +1 -1
  141. package/dist/server/lib/ticketAutomation.js +9 -11
  142. package/dist/server/lib/ticketAutomation.js.map +1 -1
  143. package/dist/server/lib/ticketAutomationCommit.js +21 -11
  144. package/dist/server/lib/ticketAutomationCommit.js.map +1 -1
  145. package/dist/server/lib/ticketFollowUpOperations.js +3 -1
  146. package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
  147. package/dist/server/lib/ticketSettingsOperations.js +9 -0
  148. package/dist/server/lib/ticketSettingsOperations.js.map +1 -1
  149. package/dist/server/lib/ticketWorkflowOperations.js +2 -6
  150. package/dist/server/lib/ticketWorkflowOperations.js.map +1 -1
  151. package/dist/server/lib/tickets.js +16 -6
  152. package/dist/server/lib/tickets.js.map +1 -1
  153. package/dist/server/lib/types.js +45 -0
  154. package/dist/server/lib/types.js.map +1 -1
  155. package/dist/server/workers/followUp.js +76 -1
  156. package/dist/server/workers/followUp.js.map +1 -1
  157. package/dist/server/workers/review.js +292 -60
  158. package/dist/server/workers/review.js.map +1 -1
  159. package/dist/server/workers/specReview.js +17 -8
  160. package/dist/server/workers/specReview.js.map +1 -1
  161. package/dist/server/workers/specSession.js +33 -23
  162. package/dist/server/workers/specSession.js.map +1 -1
  163. package/package.json +1 -1
  164. package/dist/client/assets/ActivityView-C5OrI0uK.js +0 -1
  165. package/dist/client/assets/channel-CYsnLOcX.js +0 -1
  166. package/dist/client/assets/classDiagram-4FO5ZUOK-CElk31Q4.js +0 -1
  167. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-lnAahwmt.js +0 -1
  168. package/dist/client/assets/index-1CokwSFm.css +0 -2
  169. package/dist/client/assets/index-DtefHOHC.js +0 -276
  170. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-p-kfFJi7.js +0 -1
package/dist/server/db.js CHANGED
@@ -36,6 +36,7 @@ db.exec(`
36
36
  kind TEXT NOT NULL DEFAULT 'worktree',
37
37
  reviewer_model TEXT,
38
38
  reviewer_variant TEXT,
39
+ reviewer_models_json TEXT,
39
40
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
40
41
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
41
42
  )
@@ -75,8 +76,10 @@ db.exec(`
75
76
  preview_capability_mode TEXT,
76
77
  helper_model TEXT,
77
78
  helper_variant TEXT,
79
+ helper_models_json TEXT,
78
80
  reviewer_model TEXT,
79
81
  reviewer_variant TEXT,
82
+ reviewer_models_json TEXT,
80
83
  commit_message_rules TEXT,
81
84
  commit_after_each_ticket INTEGER NOT NULL DEFAULT 0,
82
85
  auto_park_stale_tickets INTEGER NOT NULL DEFAULT 0,
@@ -146,6 +149,7 @@ ensureColumn('worktree_bundles', 'automation_pause_on_open_questions', 'INTEGER'
146
149
  ensureColumn('worktree_bundles', 'automation_review_max_iterations', 'INTEGER');
147
150
  ensureColumn('worktree_bundles', 'reviewer_model', 'TEXT');
148
151
  ensureColumn('worktree_bundles', 'reviewer_variant', 'TEXT');
152
+ ensureColumn('worktree_bundles', 'reviewer_models_json', 'TEXT');
149
153
  ensureColumn('worktree_bundles', 'required_check_policy_override', 'TEXT');
150
154
  db.exec('UPDATE worktree_bundles SET required_check_policy_override = NULL WHERE required_check_policy_override IS NOT NULL');
151
155
  ensureColumn('projects', 'worktree_sync', 'TEXT');
@@ -162,8 +166,10 @@ ensureColumn('projects', 'auto_fix_check_definition_ids', "TEXT NOT NULL DEFAULT
162
166
  ensureColumn('projects', 'test_commands', 'TEXT');
163
167
  ensureColumn('projects', 'helper_model', 'TEXT');
164
168
  ensureColumn('projects', 'helper_variant', 'TEXT');
169
+ ensureColumn('projects', 'helper_models_json', 'TEXT');
165
170
  ensureColumn('projects', 'reviewer_model', 'TEXT');
166
171
  ensureColumn('projects', 'reviewer_variant', 'TEXT');
172
+ ensureColumn('projects', 'reviewer_models_json', 'TEXT');
167
173
  ensureColumn('projects', 'commit_message_rules', 'TEXT');
168
174
  ensureColumn('projects', 'commit_after_each_ticket', 'INTEGER NOT NULL DEFAULT 0');
169
175
  ensureColumn('projects', 'preview_service_name', 'TEXT');
@@ -177,6 +183,33 @@ ensureColumn('projects', 'spec_aware_code_review_enabled', 'INTEGER NOT NULL DEF
177
183
  ensureColumn('projects', 'deletion_started_at', 'DATETIME');
178
184
  ensureColumn('projects', 'deletion_claim_id', 'TEXT');
179
185
  ensureColumn('projects', 'deletion_cleanup_started_at', 'DATETIME');
186
+ const backfillAgentModelMaps = () => {
187
+ db.transaction(() => {
188
+ db.exec(`
189
+ UPDATE projects
190
+ SET helper_models_json = CASE
191
+ WHEN helper_model IS NULL THEN '{}'
192
+ ELSE json_object('opencode', json_object('model', helper_model, 'variant', helper_variant))
193
+ END
194
+ WHERE helper_models_json IS NULL;
195
+
196
+ UPDATE projects
197
+ SET reviewer_models_json = CASE
198
+ WHEN reviewer_model IS NULL THEN '{}'
199
+ ELSE json_object('opencode', json_object('model', reviewer_model, 'variant', reviewer_variant))
200
+ END
201
+ WHERE reviewer_models_json IS NULL;
202
+
203
+ UPDATE worktree_bundles
204
+ SET reviewer_models_json = CASE
205
+ WHEN reviewer_model IS NULL THEN '{}'
206
+ ELSE json_object('opencode', json_object('model', reviewer_model, 'variant', reviewer_variant))
207
+ END
208
+ WHERE reviewer_models_json IS NULL;
209
+ `);
210
+ })();
211
+ };
212
+ backfillAgentModelMaps();
180
213
  db.exec(`
181
214
  CREATE TABLE IF NOT EXISTS execution_profile_revisions (
182
215
  id TEXT PRIMARY KEY,
@@ -5189,6 +5222,613 @@ ensureColumn('bundle_automation_state', 'automation_progression_run_id', 'TEXT')
5189
5222
  ensureColumn('bundle_automation_state', 'automation_paused_stage_run_id', 'TEXT');
5190
5223
  ensureColumn('bundle_automation_state', 'automation_paused_boundary_purpose', 'TEXT');
5191
5224
  ensureColumn('bundle_automation_state', 'automation_pause_reason_code', 'TEXT');
5225
+ db.exec('DROP TRIGGER IF EXISTS validate_review_repair_result_update');
5226
+ db.exec('DROP TRIGGER IF EXISTS validate_review_repair_gate_update');
5227
+ db.exec('DROP TRIGGER IF EXISTS validate_review_repair_gate_evaluation_update');
5228
+ db.exec('DROP TRIGGER IF EXISTS validate_review_repair_verification_update');
5229
+ db.exec('DROP TRIGGER IF EXISTS validate_review_repair_phase_update');
5230
+ db.exec(`
5231
+ CREATE TABLE IF NOT EXISTS review_repair_iterations (
5232
+ id TEXT PRIMARY KEY,
5233
+ project_id TEXT NOT NULL,
5234
+ worktree_bundle_id TEXT NOT NULL,
5235
+ owner_ticket_id TEXT NOT NULL,
5236
+ automation_progression_run_id TEXT NOT NULL,
5237
+ ordinal INTEGER NOT NULL,
5238
+ triggering_review_execution_run_id TEXT NOT NULL,
5239
+ triggering_review_run_id TEXT NOT NULL,
5240
+ action_envelope_run_id TEXT,
5241
+ action_run_id TEXT,
5242
+ gate_batch_run_id TEXT,
5243
+ gate_source_batch_run_id TEXT,
5244
+ gate_evaluation_id TEXT,
5245
+ resulting_review_execution_run_id TEXT,
5246
+ resulting_review_run_id TEXT,
5247
+ triggering_blocking_count INTEGER NOT NULL,
5248
+ resulting_blocking_count INTEGER,
5249
+ claim_effective_automation_config_json TEXT NOT NULL,
5250
+ phase TEXT NOT NULL DEFAULT 'observed',
5251
+ outcome TEXT,
5252
+ stop_reason TEXT,
5253
+ workspace_evidence_json TEXT,
5254
+ observed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
5255
+ action_claimed_at DATETIME,
5256
+ action_active_at DATETIME,
5257
+ gate_pending_at DATETIME,
5258
+ gate_active_at DATETIME,
5259
+ verification_pending_at DATETIME,
5260
+ verification_active_at DATETIME,
5261
+ paused_at DATETIME,
5262
+ terminal_at DATETIME,
5263
+ deletion_claimed_at DATETIME,
5264
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
5265
+ updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
5266
+ UNIQUE (automation_progression_run_id, ordinal),
5267
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
5268
+ FOREIGN KEY (worktree_bundle_id) REFERENCES worktree_bundles(id) ON DELETE RESTRICT,
5269
+ FOREIGN KEY (owner_ticket_id) REFERENCES tickets(id) ON DELETE RESTRICT,
5270
+ FOREIGN KEY (automation_progression_run_id, project_id) REFERENCES execution_runs(id, project_id) ON DELETE RESTRICT,
5271
+ FOREIGN KEY (triggering_review_execution_run_id, project_id) REFERENCES execution_runs(id, project_id) ON DELETE RESTRICT,
5272
+ FOREIGN KEY (triggering_review_run_id) REFERENCES review_runs(id) ON DELETE RESTRICT,
5273
+ FOREIGN KEY (action_envelope_run_id, project_id) REFERENCES execution_runs(id, project_id) ON DELETE RESTRICT,
5274
+ FOREIGN KEY (action_run_id, project_id) REFERENCES execution_runs(id, project_id) ON DELETE RESTRICT,
5275
+ FOREIGN KEY (gate_batch_run_id, project_id) REFERENCES execution_runs(id, project_id) ON DELETE RESTRICT,
5276
+ FOREIGN KEY (gate_source_batch_run_id, project_id) REFERENCES execution_runs(id, project_id) ON DELETE RESTRICT,
5277
+ FOREIGN KEY (gate_evaluation_id) REFERENCES check_gate_evaluations(id) ON DELETE RESTRICT,
5278
+ FOREIGN KEY (resulting_review_execution_run_id, project_id) REFERENCES execution_runs(id, project_id) ON DELETE RESTRICT,
5279
+ FOREIGN KEY (resulting_review_run_id) REFERENCES review_runs(id) ON DELETE RESTRICT,
5280
+ CHECK (ordinal >= 1),
5281
+ CHECK (triggering_blocking_count >= 0),
5282
+ CHECK (resulting_blocking_count IS NULL OR resulting_blocking_count >= 0),
5283
+ CHECK (COALESCE((
5284
+ json_valid(claim_effective_automation_config_json)
5285
+ AND json_type(claim_effective_automation_config_json) = 'object'
5286
+ AND length(CAST(claim_effective_automation_config_json AS BLOB)) BETWEEN 2 AND 16384
5287
+ AND json_type(claim_effective_automation_config_json, '$.depth') = 'text'
5288
+ AND json_extract(claim_effective_automation_config_json, '$.depth') IN ('manual', 'auto_review', 'auto_commit', 'auto_push', 'auto_pr')
5289
+ AND json_type(claim_effective_automation_config_json, '$.reviewFixEnabled') IN ('true', 'false')
5290
+ AND json_type(claim_effective_automation_config_json, '$.pauseOnOpenQuestions') IN ('true', 'false')
5291
+ AND json_type(claim_effective_automation_config_json, '$.reviewSeverity') = 'text'
5292
+ AND json_extract(claim_effective_automation_config_json, '$.reviewSeverity') IN ('high', 'medium', 'low')
5293
+ AND json_type(claim_effective_automation_config_json, '$.reviewMaxIterations') = 'integer'
5294
+ AND json_extract(claim_effective_automation_config_json, '$.reviewMaxIterations') BETWEEN 1 AND 10
5295
+ ), 0)),
5296
+ CHECK (workspace_evidence_json IS NULL OR (
5297
+ json_valid(workspace_evidence_json)
5298
+ AND json_type(workspace_evidence_json) = 'object'
5299
+ AND length(CAST(workspace_evidence_json AS BLOB)) BETWEEN 2 AND 65536
5300
+ )),
5301
+ CHECK (phase IN (
5302
+ 'observed', 'action_claimed', 'action_active', 'gate_pending', 'gate_active',
5303
+ 'verification_pending', 'verification_active', 'paused', 'terminal'
5304
+ )),
5305
+ CHECK (outcome IS NULL OR outcome IN (
5306
+ 'repaired', 'continuing', 'unchanged', 'exhausted', 'failed', 'cancelled',
5307
+ 'interrupted', 'paused'
5308
+ )),
5309
+ CHECK (stop_reason IS NULL OR stop_reason IN (
5310
+ 'no_blocking_findings', 'max_iterations', 'automation_disabled', 'action_failed',
5311
+ 'gate_failed', 'verification_failed', 'no_progress', 'open_questions',
5312
+ 'configuration_changed', 'invalid_lineage', 'stale_evidence', 'manual_pause',
5313
+ 'cancelled', 'interrupted'
5314
+ )),
5315
+ CHECK ((phase = 'terminal' AND outcome IS NOT NULL AND terminal_at IS NOT NULL)
5316
+ OR (phase = 'paused' AND outcome = 'paused' AND stop_reason IS NOT NULL AND paused_at IS NOT NULL)
5317
+ OR (phase NOT IN ('paused', 'terminal') AND outcome IS NULL AND stop_reason IS NULL
5318
+ AND terminal_at IS NULL)),
5319
+ CHECK (resulting_review_execution_run_id IS NULL
5320
+ OR resulting_review_execution_run_id <> triggering_review_execution_run_id),
5321
+ CHECK (resulting_review_run_id IS NULL OR resulting_review_run_id <> triggering_review_run_id),
5322
+ CHECK (gate_evaluation_id IS NULL OR gate_source_batch_run_id IS NOT NULL)
5323
+ );
5324
+
5325
+ CREATE TABLE IF NOT EXISTS review_repair_iteration_decisions (
5326
+ id TEXT PRIMARY KEY,
5327
+ iteration_id TEXT NOT NULL,
5328
+ operation_run_id TEXT,
5329
+ sequence INTEGER NOT NULL,
5330
+ decision_point TEXT NOT NULL,
5331
+ effective_automation_config_json TEXT NOT NULL,
5332
+ decision_code TEXT NOT NULL,
5333
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
5334
+ UNIQUE (iteration_id, sequence),
5335
+ FOREIGN KEY (iteration_id) REFERENCES review_repair_iterations(id) ON DELETE RESTRICT,
5336
+ CHECK (sequence >= 1),
5337
+ CHECK (decision_point IN (
5338
+ 'claim', 'action_completion', 'gate_admission', 'verification_scheduling',
5339
+ 'verification_completion', 'resume'
5340
+ )),
5341
+ CHECK (length(CAST(decision_code AS BLOB)) BETWEEN 1 AND 100),
5342
+ CHECK (COALESCE((
5343
+ json_valid(effective_automation_config_json)
5344
+ AND json_type(effective_automation_config_json) = 'object'
5345
+ AND length(CAST(effective_automation_config_json AS BLOB)) BETWEEN 2 AND 16384
5346
+ AND json_type(effective_automation_config_json, '$.depth') = 'text'
5347
+ AND json_extract(effective_automation_config_json, '$.depth') IN ('manual', 'auto_review', 'auto_commit', 'auto_push', 'auto_pr')
5348
+ AND json_type(effective_automation_config_json, '$.reviewFixEnabled') IN ('true', 'false')
5349
+ AND json_type(effective_automation_config_json, '$.pauseOnOpenQuestions') IN ('true', 'false')
5350
+ AND json_type(effective_automation_config_json, '$.reviewSeverity') = 'text'
5351
+ AND json_extract(effective_automation_config_json, '$.reviewSeverity') IN ('high', 'medium', 'low')
5352
+ AND json_type(effective_automation_config_json, '$.reviewMaxIterations') = 'integer'
5353
+ AND json_extract(effective_automation_config_json, '$.reviewMaxIterations') BETWEEN 1 AND 10
5354
+ ), 0))
5355
+ );
5356
+
5357
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_review_repair_iteration_trigger
5358
+ ON review_repair_iterations(triggering_review_execution_run_id);
5359
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_review_repair_iteration_active_progression
5360
+ ON review_repair_iterations(automation_progression_run_id)
5361
+ WHERE phase <> 'terminal';
5362
+ CREATE INDEX IF NOT EXISTS idx_review_repair_iterations_progression
5363
+ ON review_repair_iterations(automation_progression_run_id, ordinal);
5364
+ CREATE INDEX IF NOT EXISTS idx_review_repair_iterations_bundle_phase
5365
+ ON review_repair_iterations(project_id, worktree_bundle_id, phase);
5366
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_review_repair_iterations_action_envelope
5367
+ ON review_repair_iterations(action_envelope_run_id) WHERE action_envelope_run_id IS NOT NULL;
5368
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_review_repair_iterations_action
5369
+ ON review_repair_iterations(action_run_id) WHERE action_run_id IS NOT NULL;
5370
+ DROP INDEX IF EXISTS idx_review_repair_iterations_gate;
5371
+ CREATE INDEX IF NOT EXISTS idx_review_repair_iterations_gate
5372
+ ON review_repair_iterations(gate_batch_run_id) WHERE gate_batch_run_id IS NOT NULL;
5373
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_review_repair_iterations_verification
5374
+ ON review_repair_iterations(resulting_review_execution_run_id)
5375
+ WHERE resulting_review_execution_run_id IS NOT NULL;
5376
+ CREATE INDEX IF NOT EXISTS idx_review_repair_decisions_iteration
5377
+ ON review_repair_iteration_decisions(iteration_id, sequence);
5378
+
5379
+ UPDATE review_repair_iterations
5380
+ SET workspace_evidence_json = (
5381
+ SELECT json_object(
5382
+ 'policyFingerprint', evaluation.effective_policy_fingerprint,
5383
+ 'selectedBatchRunId', review_repair_iterations.gate_batch_run_id,
5384
+ 'finalSourceBatchRunId', evaluation.source_batch_run_id,
5385
+ 'gateEvaluationId', evaluation.id,
5386
+ 'workspaceIdentity', json_extract(evaluation.snapshot_json, '$.workspaceIdentity')
5387
+ )
5388
+ FROM check_gate_evaluations evaluation
5389
+ WHERE evaluation.id = review_repair_iterations.gate_evaluation_id
5390
+ AND json_type(evaluation.snapshot_json, '$.workspaceIdentity') = 'object'
5391
+ )
5392
+ WHERE workspace_evidence_json IS NULL AND gate_evaluation_id IS NOT NULL
5393
+ AND EXISTS (
5394
+ SELECT 1 FROM check_gate_evaluations evaluation
5395
+ WHERE evaluation.id = review_repair_iterations.gate_evaluation_id
5396
+ AND json_type(evaluation.snapshot_json, '$.workspaceIdentity') = 'object'
5397
+ );
5398
+
5399
+ DROP TRIGGER IF EXISTS validate_review_repair_iteration_insert;
5400
+ CREATE TRIGGER validate_review_repair_iteration_insert
5401
+ BEFORE INSERT ON review_repair_iterations
5402
+ WHEN NEW.phase <> 'observed'
5403
+ OR NEW.action_envelope_run_id IS NOT NULL
5404
+ OR NEW.action_run_id IS NOT NULL
5405
+ OR NEW.gate_batch_run_id IS NOT NULL
5406
+ OR NEW.gate_source_batch_run_id IS NOT NULL
5407
+ OR NEW.gate_evaluation_id IS NOT NULL
5408
+ OR NEW.resulting_review_execution_run_id IS NOT NULL
5409
+ OR NEW.resulting_review_run_id IS NOT NULL
5410
+ OR NEW.resulting_blocking_count IS NOT NULL
5411
+ OR NEW.outcome IS NOT NULL
5412
+ OR NEW.stop_reason IS NOT NULL
5413
+ OR NEW.action_claimed_at IS NOT NULL
5414
+ OR NEW.action_active_at IS NOT NULL
5415
+ OR NEW.gate_pending_at IS NOT NULL
5416
+ OR NEW.gate_active_at IS NOT NULL
5417
+ OR NEW.verification_pending_at IS NOT NULL
5418
+ OR NEW.verification_active_at IS NOT NULL
5419
+ OR NEW.paused_at IS NOT NULL
5420
+ OR NEW.terminal_at IS NOT NULL
5421
+ OR NOT EXISTS (
5422
+ SELECT 1 FROM projects WHERE id = NEW.project_id AND deletion_started_at IS NULL
5423
+ ) OR NOT EXISTS (
5424
+ SELECT 1 FROM worktree_bundles
5425
+ WHERE id = NEW.worktree_bundle_id AND project_id = NEW.project_id
5426
+ ) OR NOT EXISTS (
5427
+ SELECT 1 FROM tickets
5428
+ WHERE id = NEW.owner_ticket_id AND project_id = NEW.project_id
5429
+ AND worktree_bundle_id = NEW.worktree_bundle_id
5430
+ ) OR NOT EXISTS (
5431
+ SELECT 1
5432
+ FROM execution_runs progression
5433
+ JOIN execution_run_links bundle_link
5434
+ ON bundle_link.execution_run_id = progression.id
5435
+ AND bundle_link.project_id = progression.project_id
5436
+ AND bundle_link.entity_type = 'bundle'
5437
+ AND bundle_link.entity_id = NEW.worktree_bundle_id
5438
+ AND bundle_link.relationship = 'primary'
5439
+ WHERE progression.id = NEW.automation_progression_run_id
5440
+ AND progression.project_id = NEW.project_id
5441
+ AND progression.kind = 'automation_progression'
5442
+ ) OR NOT EXISTS (
5443
+ SELECT 1
5444
+ FROM execution_runs review_execution
5445
+ JOIN review_runs review ON review.id = NEW.triggering_review_run_id
5446
+ JOIN execution_run_links result_link
5447
+ ON result_link.execution_run_id = review_execution.id
5448
+ AND result_link.project_id = review_execution.project_id
5449
+ AND result_link.entity_type = 'review_run'
5450
+ AND result_link.entity_id = review.id
5451
+ AND result_link.relationship = 'result'
5452
+ JOIN execution_run_links ticket_link
5453
+ ON ticket_link.execution_run_id = review_execution.id
5454
+ AND ticket_link.project_id = review_execution.project_id
5455
+ AND ticket_link.entity_type = 'ticket'
5456
+ AND ticket_link.entity_id = NEW.owner_ticket_id
5457
+ AND ticket_link.relationship = 'primary'
5458
+ JOIN execution_run_links bundle_link
5459
+ ON bundle_link.execution_run_id = review_execution.id
5460
+ AND bundle_link.project_id = review_execution.project_id
5461
+ AND bundle_link.entity_type = 'bundle'
5462
+ AND bundle_link.entity_id = NEW.worktree_bundle_id
5463
+ AND bundle_link.relationship = 'context'
5464
+ WHERE review_execution.id = NEW.triggering_review_execution_run_id
5465
+ AND review_execution.project_id = NEW.project_id
5466
+ AND review_execution.kind = 'review'
5467
+ AND review_execution.status = 'completed'
5468
+ AND review.ticket_id = NEW.owner_ticket_id
5469
+ AND review.project_id = NEW.project_id
5470
+ AND review.worktree_bundle_id = NEW.worktree_bundle_id
5471
+ AND review.stage = 'review'
5472
+ AND review.status = 'completed'
5473
+ AND (
5474
+ review_execution.parent_run_id = NEW.automation_progression_run_id
5475
+ OR EXISTS (
5476
+ SELECT 1 FROM execution_runs progression
5477
+ WHERE progression.id = NEW.automation_progression_run_id
5478
+ AND progression.project_id = NEW.project_id
5479
+ AND progression.parent_run_id = review_execution.id
5480
+ )
5481
+ )
5482
+ )
5483
+ BEGIN
5484
+ SELECT RAISE(ABORT, 'Invalid review repair iteration ownership or triggering Review lineage');
5485
+ END;
5486
+
5487
+ CREATE TRIGGER IF NOT EXISTS validate_review_repair_iteration_config_insert
5488
+ BEFORE INSERT ON review_repair_iterations
5489
+ WHEN COALESCE((
5490
+ json_valid(NEW.claim_effective_automation_config_json)
5491
+ AND json_type(NEW.claim_effective_automation_config_json) = 'object'
5492
+ AND json_type(NEW.claim_effective_automation_config_json, '$.depth') = 'text'
5493
+ AND json_extract(NEW.claim_effective_automation_config_json, '$.depth') IN ('manual', 'auto_review', 'auto_commit', 'auto_push', 'auto_pr')
5494
+ AND json_type(NEW.claim_effective_automation_config_json, '$.reviewFixEnabled') IN ('true', 'false')
5495
+ AND json_type(NEW.claim_effective_automation_config_json, '$.pauseOnOpenQuestions') IN ('true', 'false')
5496
+ AND json_type(NEW.claim_effective_automation_config_json, '$.reviewSeverity') = 'text'
5497
+ AND json_extract(NEW.claim_effective_automation_config_json, '$.reviewSeverity') IN ('high', 'medium', 'low')
5498
+ AND json_type(NEW.claim_effective_automation_config_json, '$.reviewMaxIterations') = 'integer'
5499
+ AND json_extract(NEW.claim_effective_automation_config_json, '$.reviewMaxIterations') BETWEEN 1 AND 10
5500
+ ), 0) = 0
5501
+ BEGIN
5502
+ SELECT RAISE(ABORT, 'Invalid Review repair iteration automation configuration');
5503
+ END;
5504
+
5505
+ CREATE TRIGGER IF NOT EXISTS preserve_review_repair_iteration_claim
5506
+ BEFORE UPDATE OF id, project_id, worktree_bundle_id, owner_ticket_id,
5507
+ automation_progression_run_id, ordinal, triggering_review_execution_run_id,
5508
+ triggering_review_run_id, triggering_blocking_count,
5509
+ claim_effective_automation_config_json, observed_at, created_at
5510
+ ON review_repair_iterations
5511
+ BEGIN
5512
+ SELECT RAISE(ABORT, 'Review repair iteration claim is immutable');
5513
+ END;
5514
+
5515
+ CREATE TRIGGER IF NOT EXISTS validate_review_repair_iteration_deletion_claim
5516
+ BEFORE UPDATE OF deletion_claimed_at ON review_repair_iterations
5517
+ WHEN OLD.deletion_claimed_at IS NOT NULL
5518
+ OR NEW.deletion_claimed_at IS NULL
5519
+ OR OLD.phase <> 'terminal'
5520
+ BEGIN
5521
+ SELECT RAISE(ABORT, 'Invalid Review repair iteration deletion claim');
5522
+ END;
5523
+
5524
+ CREATE TRIGGER IF NOT EXISTS validate_review_repair_action_envelope_update
5525
+ BEFORE UPDATE OF action_envelope_run_id ON review_repair_iterations
5526
+ WHEN (OLD.action_envelope_run_id IS NOT NULL AND NEW.action_envelope_run_id IS NULL) OR (
5527
+ NEW.action_envelope_run_id IS NOT NULL AND (
5528
+ (OLD.action_envelope_run_id IS NOT NULL AND OLD.action_envelope_run_id <> NEW.action_envelope_run_id
5529
+ AND OLD.action_run_id IS NOT NULL) OR
5530
+ NOT EXISTS (
5531
+ SELECT 1 FROM execution_runs action
5532
+ JOIN execution_run_links bundle_link
5533
+ ON bundle_link.execution_run_id = action.id AND bundle_link.project_id = action.project_id
5534
+ AND bundle_link.entity_type = 'bundle' AND bundle_link.entity_id = NEW.worktree_bundle_id
5535
+ AND bundle_link.relationship = 'primary'
5536
+ WHERE action.id = NEW.action_envelope_run_id AND action.project_id = NEW.project_id
5537
+ AND action.kind = 'automation_review_fix'
5538
+ AND action.parent_run_id = NEW.automation_progression_run_id
5539
+ ) OR (OLD.action_envelope_run_id IS NOT NULL AND NOT EXISTS (
5540
+ SELECT 1 FROM execution_runs replacement JOIN execution_runs prior
5541
+ ON prior.id = OLD.action_envelope_run_id
5542
+ WHERE replacement.id = NEW.action_envelope_run_id
5543
+ AND replacement.retry_of_run_id = prior.id
5544
+ AND prior.status IN ('failed', 'cancelled', 'interrupted')
5545
+ ))
5546
+ )
5547
+ )
5548
+ BEGIN
5549
+ SELECT RAISE(ABORT, 'Invalid review repair action envelope lineage');
5550
+ END;
5551
+
5552
+ CREATE TRIGGER IF NOT EXISTS validate_review_repair_action_update
5553
+ BEFORE UPDATE OF action_run_id ON review_repair_iterations
5554
+ WHEN (OLD.action_run_id IS NOT NULL AND NEW.action_run_id IS NULL) OR (
5555
+ NEW.action_run_id IS NOT NULL AND (
5556
+ (OLD.action_run_id IS NOT NULL AND OLD.action_run_id <> NEW.action_run_id
5557
+ AND (OLD.gate_batch_run_id IS NOT NULL OR OLD.resulting_review_execution_run_id IS NOT NULL)) OR
5558
+ NOT EXISTS (
5559
+ SELECT 1 FROM execution_runs action
5560
+ JOIN execution_run_links ticket_link
5561
+ ON ticket_link.execution_run_id = action.id AND ticket_link.project_id = action.project_id
5562
+ AND ticket_link.entity_type = 'ticket' AND ticket_link.entity_id = NEW.owner_ticket_id
5563
+ AND ticket_link.relationship = 'primary'
5564
+ JOIN execution_run_links bundle_link
5565
+ ON bundle_link.execution_run_id = action.id AND bundle_link.project_id = action.project_id
5566
+ AND bundle_link.entity_type = 'bundle' AND bundle_link.entity_id = NEW.worktree_bundle_id
5567
+ AND bundle_link.relationship = 'context'
5568
+ WHERE action.id = NEW.action_run_id AND action.project_id = NEW.project_id
5569
+ AND action.kind IN ('build', 'build_follow_up')
5570
+ AND action.parent_run_id = NEW.action_envelope_run_id
5571
+ ) OR (OLD.action_run_id IS NOT NULL AND NOT EXISTS (
5572
+ SELECT 1 FROM execution_runs replacement JOIN execution_runs prior
5573
+ ON prior.id = OLD.action_run_id
5574
+ WHERE replacement.id = NEW.action_run_id
5575
+ AND replacement.retry_of_run_id = prior.id
5576
+ AND prior.status IN ('failed', 'cancelled', 'interrupted')
5577
+ ))
5578
+ )
5579
+ )
5580
+ BEGIN
5581
+ SELECT RAISE(ABORT, 'Invalid review repair action lineage');
5582
+ END;
5583
+
5584
+ CREATE TRIGGER IF NOT EXISTS validate_review_repair_gate_update
5585
+ BEFORE UPDATE OF gate_batch_run_id ON review_repair_iterations
5586
+ WHEN (OLD.gate_batch_run_id IS NOT NULL AND NEW.gate_batch_run_id IS NULL
5587
+ AND NOT (NEW.phase = 'gate_pending' AND NEW.gate_source_batch_run_id IS NULL
5588
+ AND NEW.gate_evaluation_id IS NULL AND NEW.resulting_review_execution_run_id IS NULL)) OR (
5589
+ NEW.gate_batch_run_id IS NOT NULL AND (
5590
+ (OLD.gate_batch_run_id IS NOT NULL AND OLD.gate_batch_run_id <> NEW.gate_batch_run_id
5591
+ AND (OLD.gate_evaluation_id IS NOT NULL OR OLD.resulting_review_execution_run_id IS NOT NULL)) OR
5592
+ NOT EXISTS (
5593
+ SELECT 1 FROM execution_runs batch
5594
+ JOIN check_batch_details details ON details.execution_run_id = batch.id
5595
+ WHERE batch.id = NEW.gate_batch_run_id AND batch.project_id = NEW.project_id
5596
+ AND batch.kind = 'check_batch' AND details.target_kind = 'bundle'
5597
+ AND details.target_bundle_id = NEW.worktree_bundle_id
5598
+ AND details.automation_boundary_purpose = 'automation_review'
5599
+ AND batch.initiated_by = 'automation'
5600
+ AND (OLD.gate_batch_run_id IS NOT NULL
5601
+ OR batch.parent_run_id = NEW.automation_progression_run_id)
5602
+ ) OR (OLD.gate_batch_run_id IS NOT NULL AND OLD.gate_batch_run_id <> NEW.gate_batch_run_id
5603
+ AND NOT EXISTS (
5604
+ SELECT 1 FROM check_batch_details
5605
+ WHERE execution_run_id = NEW.gate_batch_run_id
5606
+ AND rerun_of_batch_run_id = OLD.gate_batch_run_id
5607
+ ))
5608
+ ))
5609
+ BEGIN
5610
+ SELECT RAISE(ABORT, 'Invalid review repair gate batch lineage');
5611
+ END;
5612
+
5613
+ CREATE TRIGGER IF NOT EXISTS validate_review_repair_gate_evaluation_update
5614
+ BEFORE UPDATE OF gate_source_batch_run_id, gate_evaluation_id ON review_repair_iterations
5615
+ WHEN (OLD.gate_evaluation_id IS NOT NULL AND (
5616
+ NEW.gate_evaluation_id IS NULL OR NEW.gate_source_batch_run_id IS NULL
5617
+ ) AND NOT (NEW.phase = 'gate_pending' AND NEW.gate_batch_run_id IS NULL
5618
+ AND NEW.gate_evaluation_id IS NULL AND NEW.gate_source_batch_run_id IS NULL
5619
+ AND NEW.resulting_review_execution_run_id IS NULL)) OR (NEW.gate_evaluation_id IS NOT NULL AND NOT EXISTS (
5620
+ SELECT 1 FROM check_gate_evaluations evaluation
5621
+ WHERE evaluation.id = NEW.gate_evaluation_id
5622
+ AND evaluation.project_id = NEW.project_id
5623
+ AND evaluation.target_kind = 'bundle'
5624
+ AND evaluation.target_bundle_id = NEW.worktree_bundle_id
5625
+ AND evaluation.automation_progression_run_id = NEW.automation_progression_run_id
5626
+ AND evaluation.boundary_kind = 'automation_review'
5627
+ AND evaluation.source_batch_run_id = NEW.gate_source_batch_run_id
5628
+ AND evaluation.attempts_sealed = 1
5629
+ AND (NEW.gate_source_batch_run_id = NEW.gate_batch_run_id OR EXISTS (
5630
+ SELECT 1 FROM check_batch_details source
5631
+ WHERE source.execution_run_id = NEW.gate_source_batch_run_id
5632
+ AND source.rerun_of_batch_run_id = NEW.gate_batch_run_id
5633
+ ))
5634
+ ))
5635
+ BEGIN
5636
+ SELECT RAISE(ABORT, 'Invalid review repair gate evaluation lineage');
5637
+ END;
5638
+
5639
+ CREATE TRIGGER IF NOT EXISTS validate_review_repair_verification_update
5640
+ BEFORE UPDATE OF resulting_review_execution_run_id ON review_repair_iterations
5641
+ WHEN (OLD.resulting_review_execution_run_id IS NOT NULL AND NEW.resulting_review_execution_run_id IS NULL
5642
+ AND NOT (
5643
+ OLD.phase = 'paused' AND OLD.outcome = 'paused' AND OLD.stop_reason = 'stale_evidence'
5644
+ AND NEW.phase = 'gate_pending' AND NEW.gate_batch_run_id IS NULL
5645
+ AND NEW.gate_source_batch_run_id IS NULL AND NEW.gate_evaluation_id IS NULL
5646
+ AND NEW.workspace_evidence_json IS NULL AND NEW.resulting_review_run_id IS NULL
5647
+ AND NEW.resulting_blocking_count IS NULL
5648
+ AND NEW.gate_active_at IS NULL AND NEW.verification_pending_at IS NULL
5649
+ AND NEW.verification_active_at IS NULL
5650
+ )) OR (
5651
+ NEW.resulting_review_execution_run_id IS NOT NULL AND (
5652
+ (OLD.resulting_review_execution_run_id IS NOT NULL
5653
+ AND OLD.resulting_review_execution_run_id <> NEW.resulting_review_execution_run_id
5654
+ AND OLD.resulting_review_run_id IS NOT NULL
5655
+ AND NOT (NEW.resulting_review_run_id IS NULL AND EXISTS (
5656
+ SELECT 1 FROM review_runs prior_result
5657
+ WHERE prior_result.id = OLD.resulting_review_run_id
5658
+ AND prior_result.status IN ('running', 'parse_failed', 'error', 'stopped')
5659
+ ))) OR
5660
+ NEW.resulting_review_execution_run_id = NEW.triggering_review_execution_run_id OR NOT EXISTS (
5661
+ SELECT 1 FROM execution_runs verification
5662
+ JOIN execution_run_links ticket_link
5663
+ ON ticket_link.execution_run_id = verification.id AND ticket_link.project_id = verification.project_id
5664
+ AND ticket_link.entity_type = 'ticket' AND ticket_link.entity_id = NEW.owner_ticket_id
5665
+ AND ticket_link.relationship = 'primary'
5666
+ JOIN execution_run_links bundle_link
5667
+ ON bundle_link.execution_run_id = verification.id AND bundle_link.project_id = verification.project_id
5668
+ AND bundle_link.entity_type = 'bundle' AND bundle_link.entity_id = NEW.worktree_bundle_id
5669
+ AND bundle_link.relationship = 'context'
5670
+ WHERE verification.id = NEW.resulting_review_execution_run_id
5671
+ AND verification.project_id = NEW.project_id AND verification.kind = 'review'
5672
+ AND verification.parent_run_id = NEW.automation_progression_run_id
5673
+ ) OR (OLD.resulting_review_execution_run_id IS NOT NULL AND NOT EXISTS (
5674
+ SELECT 1 FROM execution_runs replacement JOIN execution_runs prior
5675
+ ON prior.id = OLD.resulting_review_execution_run_id
5676
+ WHERE replacement.id = NEW.resulting_review_execution_run_id
5677
+ AND replacement.retry_of_run_id = prior.id
5678
+ AND prior.status IN ('failed', 'cancelled', 'interrupted')
5679
+ ))
5680
+ )
5681
+ )
5682
+ BEGIN
5683
+ SELECT RAISE(ABORT, 'Invalid review repair verification lineage');
5684
+ END;
5685
+
5686
+ CREATE TRIGGER IF NOT EXISTS validate_review_repair_result_update
5687
+ BEFORE UPDATE OF resulting_review_run_id ON review_repair_iterations
5688
+ WHEN (OLD.resulting_review_run_id IS NOT NULL AND NEW.resulting_review_run_id IS NULL
5689
+ AND NOT (OLD.resulting_review_execution_run_id <> NEW.resulting_review_execution_run_id
5690
+ AND EXISTS (
5691
+ SELECT 1 FROM review_runs prior_result
5692
+ WHERE prior_result.id = OLD.resulting_review_run_id
5693
+ AND prior_result.status IN ('running', 'parse_failed', 'error', 'stopped')
5694
+ ))) OR (
5695
+ NEW.resulting_review_run_id IS NOT NULL AND (
5696
+ NEW.resulting_review_run_id = NEW.triggering_review_run_id OR NOT EXISTS (
5697
+ SELECT 1 FROM review_runs review
5698
+ JOIN execution_run_links result_link
5699
+ ON result_link.entity_type = 'review_run' AND result_link.entity_id = review.id
5700
+ AND result_link.relationship = 'result'
5701
+ WHERE review.id = NEW.resulting_review_run_id
5702
+ AND result_link.execution_run_id = NEW.resulting_review_execution_run_id
5703
+ AND result_link.project_id = NEW.project_id
5704
+ AND review.ticket_id = NEW.owner_ticket_id AND review.project_id = NEW.project_id
5705
+ AND review.worktree_bundle_id = NEW.worktree_bundle_id AND review.stage = 'review'
5706
+ AND review.status IN ('running', 'completed')
5707
+ AND EXISTS (
5708
+ SELECT 1 FROM execution_runs execution
5709
+ WHERE execution.id = NEW.resulting_review_execution_run_id
5710
+ AND execution.project_id = NEW.project_id
5711
+ AND execution.status IN ('queued', 'running', 'completed')
5712
+ )
5713
+ )
5714
+ ))
5715
+ BEGIN
5716
+ SELECT RAISE(ABORT, 'Invalid review repair resulting Review lineage');
5717
+ END;
5718
+
5719
+ CREATE TRIGGER IF NOT EXISTS validate_review_repair_terminal_update
5720
+ BEFORE UPDATE OF phase ON review_repair_iterations
5721
+ WHEN NEW.phase = 'terminal' AND NEW.outcome IN ('repaired', 'continuing', 'unchanged', 'exhausted')
5722
+ AND (
5723
+ NEW.resulting_review_execution_run_id IS NULL
5724
+ OR NEW.resulting_review_run_id IS NULL
5725
+ OR NEW.resulting_blocking_count IS NULL
5726
+ OR NOT EXISTS (
5727
+ SELECT 1 FROM execution_runs execution
5728
+ JOIN review_runs review ON review.id = NEW.resulting_review_run_id
5729
+ JOIN execution_run_links result_link
5730
+ ON result_link.execution_run_id = execution.id
5731
+ AND result_link.project_id = execution.project_id
5732
+ AND result_link.entity_type = 'review_run'
5733
+ AND result_link.entity_id = review.id
5734
+ AND result_link.relationship = 'result'
5735
+ WHERE execution.id = NEW.resulting_review_execution_run_id
5736
+ AND execution.project_id = NEW.project_id
5737
+ AND execution.kind = 'review' AND execution.status = 'completed'
5738
+ AND review.status = 'completed'
5739
+ )
5740
+ )
5741
+ BEGIN
5742
+ SELECT RAISE(ABORT, 'Completed Review repair outcomes require completed verification evidence');
5743
+ END;
5744
+
5745
+ CREATE TRIGGER IF NOT EXISTS validate_review_repair_phase_update
5746
+ BEFORE UPDATE OF phase ON review_repair_iterations
5747
+ WHEN NEW.phase <> OLD.phase
5748
+ AND NEW.phase NOT IN ('paused', 'terminal')
5749
+ AND NOT (
5750
+ (OLD.phase = 'paused' AND NEW.phase IN (
5751
+ 'observed', 'action_claimed', 'action_active', 'gate_pending', 'gate_active',
5752
+ 'verification_pending', 'verification_active'
5753
+ ))
5754
+ OR (OLD.phase = 'observed' AND NEW.phase = 'action_claimed')
5755
+ OR (OLD.phase = 'action_claimed' AND NEW.phase = 'action_active')
5756
+ OR (OLD.phase = 'action_active' AND NEW.phase = 'gate_pending')
5757
+ OR (OLD.phase = 'gate_pending' AND NEW.phase = 'gate_active')
5758
+ OR (OLD.phase = 'gate_active' AND NEW.phase = 'gate_pending'
5759
+ AND NEW.gate_batch_run_id IS NULL AND NEW.gate_source_batch_run_id IS NULL
5760
+ AND NEW.gate_evaluation_id IS NULL AND NEW.resulting_review_execution_run_id IS NULL)
5761
+ OR (OLD.phase = 'gate_active' AND NEW.phase = 'verification_pending')
5762
+ OR (OLD.phase = 'verification_pending' AND NEW.phase = 'verification_active')
5763
+ )
5764
+ BEGIN
5765
+ SELECT RAISE(ABORT, 'Invalid Review repair iteration phase transition');
5766
+ END;
5767
+
5768
+ CREATE TRIGGER IF NOT EXISTS preserve_review_repair_decision
5769
+ BEFORE UPDATE ON review_repair_iteration_decisions
5770
+ BEGIN
5771
+ SELECT RAISE(ABORT, 'Review repair iteration decisions are immutable');
5772
+ END;
5773
+
5774
+ CREATE TRIGGER IF NOT EXISTS validate_review_repair_decision_insert
5775
+ BEFORE INSERT ON review_repair_iteration_decisions
5776
+ WHEN NOT EXISTS (
5777
+ SELECT 1 FROM review_repair_iterations iteration
5778
+ JOIN projects project ON project.id = iteration.project_id
5779
+ WHERE iteration.id = NEW.iteration_id AND project.deletion_started_at IS NULL
5780
+ ) OR NEW.sequence <> COALESCE((
5781
+ SELECT MAX(sequence) + 1 FROM review_repair_iteration_decisions
5782
+ WHERE iteration_id = NEW.iteration_id
5783
+ ), 1)
5784
+ BEGIN
5785
+ SELECT RAISE(ABORT, 'Invalid Review repair iteration decision sequence');
5786
+ END;
5787
+
5788
+ CREATE TRIGGER IF NOT EXISTS validate_review_repair_decision_config_insert
5789
+ BEFORE INSERT ON review_repair_iteration_decisions
5790
+ WHEN COALESCE((
5791
+ json_valid(NEW.effective_automation_config_json)
5792
+ AND json_type(NEW.effective_automation_config_json) = 'object'
5793
+ AND json_type(NEW.effective_automation_config_json, '$.depth') = 'text'
5794
+ AND json_extract(NEW.effective_automation_config_json, '$.depth') IN ('manual', 'auto_review', 'auto_commit', 'auto_push', 'auto_pr')
5795
+ AND json_type(NEW.effective_automation_config_json, '$.reviewFixEnabled') IN ('true', 'false')
5796
+ AND json_type(NEW.effective_automation_config_json, '$.pauseOnOpenQuestions') IN ('true', 'false')
5797
+ AND json_type(NEW.effective_automation_config_json, '$.reviewSeverity') = 'text'
5798
+ AND json_extract(NEW.effective_automation_config_json, '$.reviewSeverity') IN ('high', 'medium', 'low')
5799
+ AND json_type(NEW.effective_automation_config_json, '$.reviewMaxIterations') = 'integer'
5800
+ AND json_extract(NEW.effective_automation_config_json, '$.reviewMaxIterations') BETWEEN 1 AND 10
5801
+ ), 0) = 0
5802
+ BEGIN
5803
+ SELECT RAISE(ABORT, 'Invalid Review repair decision automation configuration');
5804
+ END;
5805
+
5806
+ CREATE TRIGGER IF NOT EXISTS prevent_review_repair_iteration_delete
5807
+ BEFORE DELETE ON review_repair_iterations
5808
+ WHEN OLD.deletion_claimed_at IS NULL
5809
+ AND EXISTS (SELECT 1 FROM projects WHERE id = OLD.project_id AND deletion_started_at IS NULL)
5810
+ BEGIN
5811
+ SELECT RAISE(ABORT, 'Review repair iterations are immutable');
5812
+ END;
5813
+
5814
+ CREATE TRIGGER IF NOT EXISTS prevent_review_repair_decision_delete
5815
+ BEFORE DELETE ON review_repair_iteration_decisions
5816
+ WHEN EXISTS (
5817
+ SELECT 1 FROM review_repair_iterations iteration
5818
+ JOIN projects project ON project.id = iteration.project_id
5819
+ WHERE iteration.id = OLD.iteration_id AND iteration.deletion_claimed_at IS NULL
5820
+ AND project.deletion_started_at IS NULL
5821
+ )
5822
+ BEGIN
5823
+ SELECT RAISE(ABORT, 'Review repair iteration decisions are immutable');
5824
+ END;
5825
+ `);
5826
+ ensureColumn('review_repair_iteration_decisions', 'operation_run_id', 'TEXT');
5827
+ db.exec(`
5828
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_review_repair_decisions_operation
5829
+ ON review_repair_iteration_decisions(iteration_id, decision_point, operation_run_id)
5830
+ WHERE operation_run_id IS NOT NULL;
5831
+ `);
5192
5832
  db.exec(`
5193
5833
  CREATE TABLE IF NOT EXISTS automation_stage_details (
5194
5834
  execution_run_id TEXT PRIMARY KEY,