@straiffi/archon 1.8.7 → 1.8.9

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 (180) hide show
  1. package/dist/client/assets/{ActivityView-D4Qh96zr.js → ActivityView-gBeoYQdD.js} +1 -1
  2. package/dist/client/assets/{GitHubActionsDialog-Bg03OmVv.js → GitHubActionsDialog-fc1Vwafm.js} +1 -1
  3. package/dist/client/assets/RepositoryGraphDialog-DCOjwUR3.js +1 -0
  4. package/dist/client/assets/VerificationDialog-CIObj1Rw.js +4 -0
  5. package/dist/client/assets/{architectureDiagram-3BPJPVTR-2lxabjSl.js → architectureDiagram-3BPJPVTR-B1tJZe1S.js} +1 -1
  6. package/dist/client/assets/{blockDiagram-GPEHLZMM-C80HvJmb.js → blockDiagram-GPEHLZMM-D_90AQ2Z.js} +1 -1
  7. package/dist/client/assets/{c4Diagram-AAUBKEIU-BM3k_lKz.js → c4Diagram-AAUBKEIU-DSyJfqly.js} +1 -1
  8. package/dist/client/assets/channel-DFw1f2Rh.js +1 -0
  9. package/dist/client/assets/{chunk-2J33WTMH-BTk3lX07.js → chunk-2J33WTMH-B9RStQGj.js} +1 -1
  10. package/dist/client/assets/{chunk-3OPIFGDE-DAxdBZ_4.js → chunk-3OPIFGDE-CHKuJYq0.js} +1 -1
  11. package/dist/client/assets/{chunk-5ZQYHXKU-BYm9s62a.js → chunk-5ZQYHXKU-Cznw7LTJ.js} +1 -1
  12. package/dist/client/assets/{chunk-727SXJPM-iVUM8xuV.js → chunk-727SXJPM-ix6OeZwJ.js} +1 -1
  13. package/dist/client/assets/{chunk-AQP2D5EJ-DVM7riMJ.js → chunk-AQP2D5EJ-DrPJIcE7.js} +1 -1
  14. package/dist/client/assets/{chunk-CSCIHK7Q-_D1FzP9B.js → chunk-CSCIHK7Q-BSEHTnBR.js} +1 -1
  15. package/dist/client/assets/{chunk-KSCS5N6A-D3XouAHf.js → chunk-KSCS5N6A-MdDdaLn8.js} +1 -1
  16. package/dist/client/assets/{chunk-L5ZTLDWV-B7NYWgT4.js → chunk-L5ZTLDWV-D_5xeDG1.js} +1 -1
  17. package/dist/client/assets/{chunk-LZXEDZCA-Dgkkbb6A.js → chunk-LZXEDZCA-Bz8_Fyt2.js} +2 -2
  18. package/dist/client/assets/{chunk-ND2GUHAM-CzO1oVCi.js → chunk-ND2GUHAM-DCINKlk8.js} +1 -1
  19. package/dist/client/assets/{chunk-NZK2D7GU-re0VVZne.js → chunk-NZK2D7GU-rGPgryKx.js} +1 -1
  20. package/dist/client/assets/{chunk-O5CBEL6O-BwsS59iy.js → chunk-O5CBEL6O-BHB8UIYA.js} +1 -1
  21. package/dist/client/assets/{chunk-WU5MYG2G-CLyh-xCA.js → chunk-WU5MYG2G-Bz5BJWjF.js} +1 -1
  22. package/dist/client/assets/classDiagram-4FO5ZUOK-Dt0kmMzQ.js +1 -0
  23. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BuxhA4Gw.js +1 -0
  24. package/dist/client/assets/{dagre-BM42HDAG-x71fYlqQ.js → dagre-BM42HDAG-B4TXLkOG.js} +1 -1
  25. package/dist/client/assets/{diagram-2AECGRRQ-CMdwzuYj.js → diagram-2AECGRRQ-CxMup1wq.js} +1 -1
  26. package/dist/client/assets/{diagram-5GNKFQAL-B3l6I4qJ.js → diagram-5GNKFQAL-CTfP_wnS.js} +1 -1
  27. package/dist/client/assets/{diagram-KO2AKTUF-BNhypLBW.js → diagram-KO2AKTUF-31NKNt4r.js} +1 -1
  28. package/dist/client/assets/{diagram-LMA3HP47-CmrhbiDt.js → diagram-LMA3HP47-Cxo7yvjc.js} +1 -1
  29. package/dist/client/assets/{diagram-OG6HWLK6-CRobDMLl.js → diagram-OG6HWLK6-ChgSAMLv.js} +1 -1
  30. package/dist/client/assets/{erDiagram-TEJ5UH35-CqO7K0TS.js → erDiagram-TEJ5UH35-u6msywL_.js} +1 -1
  31. package/dist/client/assets/{flowDiagram-I6XJVG4X-CuLTJZU0.js → flowDiagram-I6XJVG4X-CimeXkDN.js} +1 -1
  32. package/dist/client/assets/{ganttDiagram-6RSMTGT7-Bm7v1eRG.js → ganttDiagram-6RSMTGT7-DOu5sDUI.js} +1 -1
  33. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-CNHZr-5i.js → gitGraphDiagram-PVQCEYII-zIToibUf.js} +1 -1
  34. package/dist/client/assets/index-C-VHd0Pr.js +274 -0
  35. package/dist/client/assets/index-D3xlEyeM.css +2 -0
  36. package/dist/client/assets/{infoDiagram-5YYISTIA-z27pUr2X.js → infoDiagram-5YYISTIA-CAtWGGJI.js} +1 -1
  37. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CDocZ0jf.js → ishikawaDiagram-YF4QCWOH-7N-C7DEt.js} +1 -1
  38. package/dist/client/assets/{journeyDiagram-JHISSGLW-CgP31lsU.js → journeyDiagram-JHISSGLW-D7VUypFG.js} +1 -1
  39. package/dist/client/assets/{kanban-definition-UN3LZRKU-DxTm1_fc.js → kanban-definition-UN3LZRKU-AmbDmzSD.js} +1 -1
  40. package/dist/client/assets/{line-hrZ7m44_.js → line-qf4UZ8vh.js} +1 -1
  41. package/dist/client/assets/{mermaid-parser.core-BThJAIK-.js → mermaid-parser.core-BssCd1kF.js} +1 -1
  42. package/dist/client/assets/{mermaid.core-CfVyP_kK.js → mermaid.core-DzeMqg9Y.js} +3 -3
  43. package/dist/client/assets/{mindmap-definition-RKZ34NQL-CuISnLgW.js → mindmap-definition-RKZ34NQL-dEnNQcDm.js} +1 -1
  44. package/dist/client/assets/{pieDiagram-4H26LBE5-DnWAdd44.js → pieDiagram-4H26LBE5-VjMue0a-.js} +1 -1
  45. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-Cb-RVl5A.js → quadrantDiagram-W4KKPZXB-DQFdm-0f.js} +1 -1
  46. package/dist/client/assets/{requirementDiagram-4Y6WPE33-DrXg_gCS.js → requirementDiagram-4Y6WPE33-CHIaXlsy.js} +1 -1
  47. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-DzZjp_ZP.js → sankeyDiagram-5OEKKPKP-D-kzGaKb.js} +1 -1
  48. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-CQJ3PhQD.js → sequenceDiagram-3UESZ5HK-CiDmlD8k.js} +1 -1
  49. package/dist/client/assets/{stateDiagram-AJRCARHV-B16j9pg1.js → stateDiagram-AJRCARHV-BKlnnFdT.js} +1 -1
  50. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DhJxc4em.js +1 -0
  51. package/dist/client/assets/{timeline-definition-PNZ67QCA-bUG3mZQt.js → timeline-definition-PNZ67QCA-D-BK07Un.js} +1 -1
  52. package/dist/client/assets/{vennDiagram-CIIHVFJN-DALCJcZD.js → vennDiagram-CIIHVFJN-CB9_GqSx.js} +1 -1
  53. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DPQd3l9A.js → wardleyDiagram-YWT4CUSO-BEuNfyLT.js} +1 -1
  54. package/dist/client/assets/{xychartDiagram-2RQKCTM6-BIv1FqXG.js → xychartDiagram-2RQKCTM6-CSS5WMrZ.js} +1 -1
  55. package/dist/client/index.html +2 -2
  56. package/dist/server/db.js +481 -27
  57. package/dist/server/db.js.map +1 -1
  58. package/dist/server/index.js +113 -54
  59. package/dist/server/index.js.map +1 -1
  60. package/dist/server/lib/activeAutomationChild.js +1 -0
  61. package/dist/server/lib/activeAutomationChild.js.map +1 -1
  62. package/dist/server/lib/agent.js +127 -15
  63. package/dist/server/lib/agent.js.map +1 -1
  64. package/dist/server/lib/agentRuns.js +12 -0
  65. package/dist/server/lib/agentRuns.js.map +1 -1
  66. package/dist/server/lib/agentSpawnPermits.js +37 -0
  67. package/dist/server/lib/agentSpawnPermits.js.map +1 -0
  68. package/dist/server/lib/automationCheckGate.js +9 -1
  69. package/dist/server/lib/automationCheckGate.js.map +1 -1
  70. package/dist/server/lib/automationProgression.js +19 -5
  71. package/dist/server/lib/automationProgression.js.map +1 -1
  72. package/dist/server/lib/automationReviewGate.js +1 -0
  73. package/dist/server/lib/automationReviewGate.js.map +1 -1
  74. package/dist/server/lib/buildCompletionContinuation.js +144 -4
  75. package/dist/server/lib/buildCompletionContinuation.js.map +1 -1
  76. package/dist/server/lib/buildSequences.js +13 -1
  77. package/dist/server/lib/buildSequences.js.map +1 -1
  78. package/dist/server/lib/bundleActivity.js +19 -0
  79. package/dist/server/lib/bundleActivity.js.map +1 -1
  80. package/dist/server/lib/chatOperations.js +81 -2
  81. package/dist/server/lib/chatOperations.js.map +1 -1
  82. package/dist/server/lib/checkAutoFix.js +604 -0
  83. package/dist/server/lib/checkAutoFix.js.map +1 -0
  84. package/dist/server/lib/checkAutoFixDetails.js +83 -0
  85. package/dist/server/lib/checkAutoFixDetails.js.map +1 -0
  86. package/dist/server/lib/checkAutoFixPolicy.js +59 -0
  87. package/dist/server/lib/checkAutoFixPolicy.js.map +1 -0
  88. package/dist/server/lib/checkRepair.js +149 -54
  89. package/dist/server/lib/checkRepair.js.map +1 -1
  90. package/dist/server/lib/checkRepairDispatch.js +91 -0
  91. package/dist/server/lib/checkRepairDispatch.js.map +1 -0
  92. package/dist/server/lib/checkRepairEvidence.js +84 -0
  93. package/dist/server/lib/checkRepairEvidence.js.map +1 -0
  94. package/dist/server/lib/checkRepairParent.js +21 -0
  95. package/dist/server/lib/checkRepairParent.js.map +1 -0
  96. package/dist/server/lib/checkRepairReconciliation.js +14 -5
  97. package/dist/server/lib/checkRepairReconciliation.js.map +1 -1
  98. package/dist/server/lib/checkRunner.js +27 -8
  99. package/dist/server/lib/checkRunner.js.map +1 -1
  100. package/dist/server/lib/checkRuns.js +63 -4
  101. package/dist/server/lib/checkRuns.js.map +1 -1
  102. package/dist/server/lib/executionReconciliation.js +387 -8
  103. package/dist/server/lib/executionReconciliation.js.map +1 -1
  104. package/dist/server/lib/executionRuns.js +24 -1
  105. package/dist/server/lib/executionRuns.js.map +1 -1
  106. package/dist/server/lib/git.js +302 -11
  107. package/dist/server/lib/git.js.map +1 -1
  108. package/dist/server/lib/integrations/github.js +138 -65
  109. package/dist/server/lib/integrations/github.js.map +1 -1
  110. package/dist/server/lib/integrations/importedIssueImages.js +10 -15
  111. package/dist/server/lib/integrations/importedIssueImages.js.map +1 -1
  112. package/dist/server/lib/postBuildCheckRuns.js +200 -5
  113. package/dist/server/lib/postBuildCheckRuns.js.map +1 -1
  114. package/dist/server/lib/postBuildChecks.js +83 -13
  115. package/dist/server/lib/postBuildChecks.js.map +1 -1
  116. package/dist/server/lib/projects.js +25 -1
  117. package/dist/server/lib/projects.js.map +1 -1
  118. package/dist/server/lib/queue.js +9 -3
  119. package/dist/server/lib/queue.js.map +1 -1
  120. package/dist/server/lib/repositoryGraphQueries.js +5 -3
  121. package/dist/server/lib/repositoryGraphQueries.js.map +1 -1
  122. package/dist/server/lib/repositoryGraphScan.js +13 -2
  123. package/dist/server/lib/repositoryGraphScan.js.map +1 -1
  124. package/dist/server/lib/repositoryGraphStore.js +61 -1
  125. package/dist/server/lib/repositoryGraphStore.js.map +1 -1
  126. package/dist/server/lib/specArtifact.js +10 -1
  127. package/dist/server/lib/specArtifact.js.map +1 -1
  128. package/dist/server/lib/specDraft.js +10 -2
  129. package/dist/server/lib/specDraft.js.map +1 -1
  130. package/dist/server/lib/specExport.js +70 -6
  131. package/dist/server/lib/specExport.js.map +1 -1
  132. package/dist/server/lib/specFormatting.js +3 -2
  133. package/dist/server/lib/specFormatting.js.map +1 -1
  134. package/dist/server/lib/specRepositoryEvidenceFormatting.js +75 -0
  135. package/dist/server/lib/specRepositoryEvidenceFormatting.js.map +1 -0
  136. package/dist/server/lib/specRepositoryImpact.js +447 -0
  137. package/dist/server/lib/specRepositoryImpact.js.map +1 -0
  138. package/dist/server/lib/specRepositoryImpactLimits.js +6 -0
  139. package/dist/server/lib/specRepositoryImpactLimits.js.map +1 -0
  140. package/dist/server/lib/specReviewContext.js +15 -5
  141. package/dist/server/lib/specReviewContext.js.map +1 -1
  142. package/dist/server/lib/specReviewValidation.js +1 -1
  143. package/dist/server/lib/specReviewValidation.js.map +1 -1
  144. package/dist/server/lib/specSections.js +28 -3
  145. package/dist/server/lib/specSections.js.map +1 -1
  146. package/dist/server/lib/specSnapshotEvidence.js +162 -0
  147. package/dist/server/lib/specSnapshotEvidence.js.map +1 -0
  148. package/dist/server/lib/specSnapshotEvidenceSerialization.js +202 -0
  149. package/dist/server/lib/specSnapshotEvidenceSerialization.js.map +1 -0
  150. package/dist/server/lib/specs.js +31 -5
  151. package/dist/server/lib/specs.js.map +1 -1
  152. package/dist/server/lib/ticketAutomationCommit.js +3 -1
  153. package/dist/server/lib/ticketAutomationCommit.js.map +1 -1
  154. package/dist/server/lib/ticketFollowUpOperations.js +16 -12
  155. package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
  156. package/dist/server/lib/ticketRunOperations.js +13 -1
  157. package/dist/server/lib/ticketRunOperations.js.map +1 -1
  158. package/dist/server/lib/ticketWorkflowOperations.js +5 -2
  159. package/dist/server/lib/ticketWorkflowOperations.js.map +1 -1
  160. package/dist/server/lib/types.js +1 -0
  161. package/dist/server/lib/types.js.map +1 -1
  162. package/dist/server/workers/build.js +46 -148
  163. package/dist/server/workers/build.js.map +1 -1
  164. package/dist/server/workers/chat.js +141 -31
  165. package/dist/server/workers/chat.js.map +1 -1
  166. package/dist/server/workers/followUp.js +210 -48
  167. package/dist/server/workers/followUp.js.map +1 -1
  168. package/dist/server/workers/specReview.js +17 -4
  169. package/dist/server/workers/specReview.js.map +1 -1
  170. package/dist/server/workers/specSession.js +127 -22
  171. package/dist/server/workers/specSession.js.map +1 -1
  172. package/package.json +1 -1
  173. package/dist/client/assets/RepositoryGraphDialog-CS_hOqPw.js +0 -1
  174. package/dist/client/assets/VerificationDialog-BYH-Ek8n.js +0 -4
  175. package/dist/client/assets/channel-HjENOCZ0.js +0 -1
  176. package/dist/client/assets/classDiagram-4FO5ZUOK-DnhdaVrK.js +0 -1
  177. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-C-BjeSGJ.js +0 -1
  178. package/dist/client/assets/index-Bs5SQZhz.css +0 -2
  179. package/dist/client/assets/index-LGNsdNYM.js +0 -274
  180. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-vNiFfHwm.js +0 -1
package/dist/server/db.js CHANGED
@@ -61,6 +61,7 @@ db.exec(`
61
61
  required_check_definition_ids TEXT NOT NULL DEFAULT '[]',
62
62
  pre_review_check_definition_ids TEXT NOT NULL DEFAULT '[]',
63
63
  post_build_check_definition_ids TEXT NOT NULL DEFAULT '[]',
64
+ auto_fix_check_definition_ids TEXT NOT NULL DEFAULT '[]',
64
65
  test_commands TEXT,
65
66
  run_ide TEXT,
66
67
  preview_service_name TEXT,
@@ -144,6 +145,7 @@ ensureColumn('projects', 'check_definitions', 'TEXT');
144
145
  ensureColumn('projects', 'required_check_definition_ids', "TEXT NOT NULL DEFAULT '[]'");
145
146
  ensureColumn('projects', 'pre_review_check_definition_ids', "TEXT NOT NULL DEFAULT '[]'");
146
147
  ensureColumn('projects', 'post_build_check_definition_ids', "TEXT NOT NULL DEFAULT '[]'");
148
+ ensureColumn('projects', 'auto_fix_check_definition_ids', "TEXT NOT NULL DEFAULT '[]'");
147
149
  ensureColumn('projects', 'test_commands', 'TEXT');
148
150
  ensureColumn('projects', 'helper_model', 'TEXT');
149
151
  ensureColumn('projects', 'helper_variant', 'TEXT');
@@ -1213,6 +1215,7 @@ db.exec(`
1213
1215
  tickets_json TEXT,
1214
1216
  dependencies_json TEXT,
1215
1217
  resource_urls_json TEXT,
1218
+ repository_evidence_json TEXT,
1216
1219
  mermaid TEXT,
1217
1220
  mockup TEXT,
1218
1221
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
@@ -1223,6 +1226,65 @@ ensureColumn('spec_snapshots', 'plan_text', 'TEXT');
1223
1226
  ensureColumn('spec_snapshots', 'mockup', 'TEXT');
1224
1227
  ensureColumn('spec_snapshots', 'file_relation_graph', 'TEXT');
1225
1228
  ensureColumn('spec_snapshots', 'resource_urls_json', 'TEXT');
1229
+ ensureColumn('spec_snapshots', 'repository_evidence_json', 'TEXT');
1230
+ db.exec(`
1231
+ DELETE FROM repository_graph_scan_references
1232
+ WHERE reference_type = 'spec_snapshot'
1233
+ AND NOT EXISTS (
1234
+ SELECT 1
1235
+ FROM spec_snapshots
1236
+ INNER JOIN spec_sessions ON spec_sessions.id = spec_snapshots.spec_session_id
1237
+ INNER JOIN repository_graph_scans
1238
+ ON repository_graph_scans.id = repository_graph_scan_references.scan_id
1239
+ AND repository_graph_scans.project_id = repository_graph_scan_references.project_id
1240
+ WHERE spec_snapshots.id = repository_graph_scan_references.reference_id
1241
+ AND spec_sessions.project_id = repository_graph_scan_references.project_id
1242
+ AND repository_graph_scans.status = 'completed'
1243
+ );
1244
+
1245
+ DROP TRIGGER IF EXISTS validate_spec_snapshot_graph_reference_insert;
1246
+ DROP TRIGGER IF EXISTS reject_spec_snapshot_graph_reference_update;
1247
+ DROP TRIGGER IF EXISTS delete_spec_snapshot_graph_reference;
1248
+ DROP TRIGGER IF EXISTS reject_spec_snapshot_repository_evidence_update;
1249
+
1250
+ CREATE TRIGGER validate_spec_snapshot_graph_reference_insert
1251
+ BEFORE INSERT ON repository_graph_scan_references
1252
+ WHEN NEW.reference_type = 'spec_snapshot' AND NOT EXISTS (
1253
+ SELECT 1
1254
+ FROM spec_snapshots
1255
+ INNER JOIN spec_sessions ON spec_sessions.id = spec_snapshots.spec_session_id
1256
+ INNER JOIN repository_graph_scans
1257
+ ON repository_graph_scans.id = NEW.scan_id
1258
+ AND repository_graph_scans.project_id = NEW.project_id
1259
+ WHERE spec_snapshots.id = NEW.reference_id
1260
+ AND spec_sessions.project_id = NEW.project_id
1261
+ AND repository_graph_scans.status = 'completed'
1262
+ )
1263
+ BEGIN
1264
+ SELECT RAISE(ABORT, 'Spec snapshot graph reference requires an owned snapshot and completed scan');
1265
+ END;
1266
+
1267
+ CREATE TRIGGER reject_spec_snapshot_graph_reference_update
1268
+ BEFORE UPDATE ON repository_graph_scan_references
1269
+ WHEN OLD.reference_type = 'spec_snapshot' OR NEW.reference_type = 'spec_snapshot'
1270
+ BEGIN
1271
+ SELECT RAISE(ABORT, 'Spec snapshot graph references are immutable');
1272
+ END;
1273
+
1274
+ CREATE TRIGGER delete_spec_snapshot_graph_reference
1275
+ AFTER DELETE ON spec_snapshots
1276
+ BEGIN
1277
+ DELETE FROM repository_graph_scan_references
1278
+ WHERE reference_type = 'spec_snapshot' AND reference_id = OLD.id;
1279
+ END;
1280
+
1281
+ CREATE TRIGGER reject_spec_snapshot_repository_evidence_update
1282
+ BEFORE UPDATE OF repository_evidence_json ON spec_snapshots
1283
+ WHEN OLD.repository_evidence_json IS NOT NEW.repository_evidence_json
1284
+ BEGIN
1285
+ SELECT RAISE(ABORT, 'Spec snapshot repository evidence is immutable');
1286
+ END;
1287
+ `);
1226
1288
  db.exec(`
1227
1289
  CREATE TABLE IF NOT EXISTS spec_message_attachments (
1228
1290
  attachment_id TEXT PRIMARY KEY,
@@ -2463,12 +2525,27 @@ db.exec(`
2463
2525
  END;
2464
2526
  `);
2465
2527
  db.exec(`
2528
+ CREATE TABLE IF NOT EXISTS agent_spawn_permits (
2529
+ id TEXT PRIMARY KEY,
2530
+ execution_run_id TEXT NOT NULL UNIQUE,
2531
+ status TEXT NOT NULL DEFAULT 'active',
2532
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
2533
+ revoked_at DATETIME,
2534
+ FOREIGN KEY (execution_run_id) REFERENCES execution_runs(id) ON DELETE CASCADE,
2535
+ CHECK (status IN ('active', 'revoked')),
2536
+ CHECK ((status = 'active' AND revoked_at IS NULL) OR (status = 'revoked' AND revoked_at IS NOT NULL))
2537
+ );
2538
+
2466
2539
  CREATE TABLE IF NOT EXISTS check_repair_details (
2467
2540
  execution_run_id TEXT PRIMARY KEY,
2468
2541
  source_batch_run_id TEXT NOT NULL,
2469
2542
  target_kind TEXT NOT NULL,
2470
2543
  target_bundle_id TEXT,
2471
- ticket_id TEXT NOT NULL,
2544
+ owner_type TEXT NOT NULL,
2545
+ owner_id TEXT NOT NULL,
2546
+ ticket_id TEXT,
2547
+ causal_execution_run_id TEXT NOT NULL,
2548
+ causal_agent_run_id TEXT NOT NULL,
2472
2549
  automation_progression_run_id TEXT,
2473
2550
  automation_boundary_purpose TEXT,
2474
2551
  initial_workspace_identity_json TEXT NOT NULL,
@@ -2484,11 +2561,16 @@ db.exec(`
2484
2561
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
2485
2562
  FOREIGN KEY (execution_run_id) REFERENCES execution_runs(id) ON DELETE CASCADE,
2486
2563
  FOREIGN KEY (source_batch_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2564
+ FOREIGN KEY (causal_execution_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2565
+ FOREIGN KEY (causal_agent_run_id) REFERENCES agent_runs(id) ON DELETE RESTRICT,
2487
2566
  FOREIGN KEY (automation_progression_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2488
2567
  FOREIGN KEY (follow_up_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2489
2568
  FOREIGN KEY (rerun_batch_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2490
2569
  FOREIGN KEY (retry_of_check_repair_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2491
2570
  CHECK (target_kind IN ('repo_root', 'bundle')),
2571
+ CHECK (owner_type IN ('ticket', 'chat_session')),
2572
+ CHECK ((owner_type = 'ticket' AND ticket_id = owner_id)
2573
+ OR (owner_type = 'chat_session' AND ticket_id IS NULL)),
2492
2574
  CHECK ((target_kind = 'repo_root' AND target_bundle_id IS NULL)
2493
2575
  OR (target_kind = 'bundle' AND target_bundle_id IS NOT NULL AND length(trim(target_bundle_id)) > 0)),
2494
2576
  CHECK (length(configuration_fingerprint) = 64 AND configuration_fingerprint NOT GLOB '*[^0-9a-f]*'),
@@ -2505,6 +2587,236 @@ db.exec(`
2505
2587
  CHECK (terminal_result IS NULL OR terminal_result IN ('passed', 'failed', 'cancelled', 'interrupted')),
2506
2588
  CHECK (terminal_message IS NULL OR length(CAST(terminal_message AS BLOB)) <= 16384)
2507
2589
  );
2590
+ `);
2591
+ const checkRepairSchema = db.prepare(`
2592
+ SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'check_repair_details'
2593
+ `).get();
2594
+ if (checkRepairSchema && !checkRepairSchema.sql.includes('owner_type')) {
2595
+ db.transaction(() => {
2596
+ db.exec(`
2597
+ DROP TRIGGER IF EXISTS preserve_check_repair_provenance;
2598
+ DROP TRIGGER IF EXISTS validate_check_repair_details_insert;
2599
+ DROP TRIGGER IF EXISTS validate_check_repair_follow_up_update;
2600
+ DROP TRIGGER IF EXISTS validate_check_repair_rerun_update;
2601
+ DROP TRIGGER IF EXISTS preserve_check_repair_terminal_result;
2602
+ DROP TRIGGER IF EXISTS preserve_check_repair_diagnostic_provenance;
2603
+ DROP TRIGGER IF EXISTS preserve_check_repair_raw_output_provenance;
2604
+ DROP TRIGGER IF EXISTS prevent_check_repair_raw_output_provenance_delete;
2605
+ DROP TRIGGER IF EXISTS validate_check_repair_diagnostic_provenance_insert;
2606
+ DROP TRIGGER IF EXISTS validate_check_repair_raw_output_provenance_insert;
2607
+ CREATE TEMP TABLE check_repair_diagnostic_provenance_migration AS
2608
+ SELECT * FROM check_repair_diagnostic_provenance;
2609
+ CREATE TEMP TABLE check_repair_raw_output_provenance_migration AS
2610
+ SELECT * FROM check_repair_raw_output_provenance;
2611
+ DROP TABLE check_repair_diagnostic_provenance;
2612
+ DROP TABLE check_repair_raw_output_provenance;
2613
+ ALTER TABLE check_repair_details RENAME TO check_repair_details_legacy;
2614
+
2615
+ CREATE TABLE check_repair_details (
2616
+ execution_run_id TEXT PRIMARY KEY,
2617
+ source_batch_run_id TEXT NOT NULL,
2618
+ target_kind TEXT NOT NULL,
2619
+ target_bundle_id TEXT,
2620
+ owner_type TEXT NOT NULL,
2621
+ owner_id TEXT NOT NULL,
2622
+ ticket_id TEXT,
2623
+ causal_execution_run_id TEXT NOT NULL,
2624
+ causal_agent_run_id TEXT NOT NULL,
2625
+ automation_progression_run_id TEXT,
2626
+ automation_boundary_purpose TEXT,
2627
+ initial_workspace_identity_json TEXT NOT NULL,
2628
+ configuration_fingerprint TEXT NOT NULL,
2629
+ effective_policy_fingerprint TEXT,
2630
+ definition_ids_json TEXT NOT NULL,
2631
+ follow_up_run_id TEXT,
2632
+ rerun_batch_run_id TEXT,
2633
+ terminal_result TEXT,
2634
+ terminal_message TEXT,
2635
+ retry_of_check_repair_run_id TEXT,
2636
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
2637
+ updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
2638
+ FOREIGN KEY (execution_run_id) REFERENCES execution_runs(id) ON DELETE CASCADE,
2639
+ FOREIGN KEY (source_batch_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2640
+ FOREIGN KEY (causal_execution_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2641
+ FOREIGN KEY (causal_agent_run_id) REFERENCES agent_runs(id) ON DELETE RESTRICT,
2642
+ FOREIGN KEY (automation_progression_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2643
+ FOREIGN KEY (follow_up_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2644
+ FOREIGN KEY (rerun_batch_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2645
+ FOREIGN KEY (retry_of_check_repair_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2646
+ CHECK (target_kind IN ('repo_root', 'bundle')),
2647
+ CHECK (owner_type IN ('ticket', 'chat_session')),
2648
+ CHECK ((owner_type = 'ticket' AND ticket_id = owner_id)
2649
+ OR (owner_type = 'chat_session' AND ticket_id IS NULL)),
2650
+ CHECK ((target_kind = 'repo_root' AND target_bundle_id IS NULL)
2651
+ OR (target_kind = 'bundle' AND target_bundle_id IS NOT NULL AND length(trim(target_bundle_id)) > 0)),
2652
+ CHECK (length(configuration_fingerprint) = 64 AND configuration_fingerprint NOT GLOB '*[^0-9a-f]*'),
2653
+ CHECK (effective_policy_fingerprint IS NULL OR (
2654
+ length(effective_policy_fingerprint) = 64 AND effective_policy_fingerprint NOT GLOB '*[^0-9a-f]*'
2655
+ )),
2656
+ CHECK (automation_boundary_purpose IS NULL OR automation_boundary_purpose IN (
2657
+ 'automation_review', 'automation_commit', 'automation_push', 'automation_pull_request'
2658
+ )),
2659
+ CHECK ((automation_progression_run_id IS NULL AND automation_boundary_purpose IS NULL)
2660
+ OR (automation_progression_run_id IS NOT NULL AND automation_boundary_purpose IS NOT NULL)),
2661
+ CHECK ((automation_progression_run_id IS NULL AND effective_policy_fingerprint IS NULL)
2662
+ OR (automation_progression_run_id IS NOT NULL AND effective_policy_fingerprint IS NOT NULL)),
2663
+ CHECK (terminal_result IS NULL OR terminal_result IN ('passed', 'failed', 'cancelled', 'interrupted')),
2664
+ CHECK (terminal_message IS NULL OR length(CAST(terminal_message AS BLOB)) <= 16384)
2665
+ );
2666
+
2667
+ CREATE TEMP TABLE check_repair_causal_migration AS
2668
+ SELECT legacy.execution_run_id AS repair_run_id,
2669
+ (
2670
+ SELECT candidate.id
2671
+ FROM execution_runs candidate
2672
+ JOIN execution_run_links owner_link ON owner_link.execution_run_id = candidate.id
2673
+ AND owner_link.project_id = candidate.project_id
2674
+ AND owner_link.relationship = 'primary'
2675
+ AND owner_link.entity_type = 'ticket'
2676
+ AND owner_link.entity_id = legacy.ticket_id
2677
+ WHERE candidate.project_id = source.project_id
2678
+ AND candidate.kind IN ('build', 'build_follow_up')
2679
+ AND candidate.id IS NOT legacy.follow_up_run_id
2680
+ AND candidate.parent_run_id IS NOT legacy.execution_run_id
2681
+ AND candidate.created_at <= source.created_at
2682
+ AND EXISTS (SELECT 1 FROM agent_runs agent WHERE agent.execution_run_id = candidate.id)
2683
+ ORDER BY candidate.created_at DESC, candidate.id DESC
2684
+ LIMIT 1
2685
+ ) AS causal_execution_run_id
2686
+ FROM check_repair_details_legacy legacy
2687
+ JOIN execution_runs source ON source.id = legacy.source_batch_run_id;
2688
+
2689
+ INSERT INTO check_repair_details (
2690
+ execution_run_id, source_batch_run_id, target_kind, target_bundle_id,
2691
+ owner_type, owner_id, ticket_id, causal_execution_run_id, causal_agent_run_id,
2692
+ automation_progression_run_id, automation_boundary_purpose, initial_workspace_identity_json,
2693
+ configuration_fingerprint, effective_policy_fingerprint, definition_ids_json,
2694
+ follow_up_run_id, rerun_batch_run_id, terminal_result, terminal_message,
2695
+ retry_of_check_repair_run_id, created_at, updated_at
2696
+ )
2697
+ SELECT legacy.execution_run_id, legacy.source_batch_run_id, legacy.target_kind, legacy.target_bundle_id,
2698
+ 'ticket', legacy.ticket_id, legacy.ticket_id,
2699
+ causal_run.id, causal_agent.id,
2700
+ legacy.automation_progression_run_id, legacy.automation_boundary_purpose,
2701
+ legacy.initial_workspace_identity_json, legacy.configuration_fingerprint,
2702
+ legacy.effective_policy_fingerprint, legacy.definition_ids_json, legacy.follow_up_run_id,
2703
+ legacy.rerun_batch_run_id, legacy.terminal_result, legacy.terminal_message,
2704
+ legacy.retry_of_check_repair_run_id, legacy.created_at, legacy.updated_at
2705
+ FROM check_repair_details_legacy legacy
2706
+ JOIN execution_runs source ON source.id = legacy.source_batch_run_id
2707
+ JOIN check_repair_causal_migration causal ON causal.repair_run_id = legacy.execution_run_id
2708
+ JOIN execution_runs causal_run ON causal_run.id = causal.causal_execution_run_id
2709
+ AND causal_run.project_id = source.project_id
2710
+ AND causal_run.kind IN ('build', 'build_follow_up')
2711
+ JOIN agent_runs causal_agent ON causal_agent.id = (
2712
+ SELECT candidate_agent.id FROM agent_runs candidate_agent
2713
+ WHERE candidate_agent.execution_run_id = causal_run.id
2714
+ ORDER BY CASE WHEN candidate_agent.role = 'main' THEN 0 ELSE 1 END,
2715
+ candidate_agent.run_index ASC, candidate_agent.created_at ASC, candidate_agent.id ASC
2716
+ LIMIT 1
2717
+ )
2718
+ JOIN tickets owner ON owner.id = legacy.ticket_id AND owner.project_id = source.project_id
2719
+ ;
2720
+
2721
+ CREATE TEMP TABLE check_repair_unrecoverable_migration AS
2722
+ SELECT legacy.execution_run_id AS repair_run_id, repair.project_id, legacy.ticket_id,
2723
+ legacy.follow_up_run_id
2724
+ FROM check_repair_details_legacy legacy
2725
+ JOIN execution_runs repair ON repair.id = legacy.execution_run_id AND repair.kind = 'check_repair'
2726
+ LEFT JOIN check_repair_details migrated ON migrated.execution_run_id = legacy.execution_run_id
2727
+ WHERE migrated.execution_run_id IS NULL;
2728
+
2729
+ CREATE TEMP TABLE check_repair_unrecoverable_children_migration AS
2730
+ SELECT child.id AS child_run_id, unrecoverable.project_id, unrecoverable.ticket_id
2731
+ FROM check_repair_unrecoverable_migration unrecoverable
2732
+ JOIN execution_runs child ON child.id = unrecoverable.follow_up_run_id
2733
+ AND child.project_id = unrecoverable.project_id
2734
+ AND child.parent_run_id = unrecoverable.repair_run_id
2735
+ AND child.kind = 'build_follow_up'
2736
+ AND child.status IN ('queued', 'running', 'waiting')
2737
+ JOIN execution_run_links owner_link ON owner_link.execution_run_id = child.id
2738
+ AND owner_link.project_id = child.project_id
2739
+ AND owner_link.entity_type = 'ticket'
2740
+ AND owner_link.entity_id = unrecoverable.ticket_id
2741
+ AND owner_link.relationship = 'primary';
2742
+
2743
+ UPDATE agent_runs
2744
+ SET agent_status = 'error', response_text = COALESCE(response_text, streaming_response),
2745
+ streaming_response = NULL,
2746
+ failure_message = 'Legacy check repair causal provenance could not be recovered',
2747
+ completed_at = COALESCE(completed_at, CURRENT_TIMESTAMP), updated_at = CURRENT_TIMESTAMP
2748
+ WHERE execution_run_id IN (
2749
+ SELECT child_run_id FROM check_repair_unrecoverable_children_migration
2750
+ ) AND agent_status = 'running' AND completed_at IS NULL;
2751
+
2752
+ UPDATE execution_runs
2753
+ SET status = 'interrupted', domain_status = 'interrupted',
2754
+ failure_code = 'legacy_repair_provenance_unavailable',
2755
+ failure_message = 'Legacy check repair causal provenance could not be recovered',
2756
+ completed_at = COALESCE(completed_at, CURRENT_TIMESTAMP), updated_at = CURRENT_TIMESTAMP
2757
+ WHERE id IN (
2758
+ SELECT child_run_id FROM check_repair_unrecoverable_children_migration
2759
+ ) AND status IN ('queued', 'running', 'waiting');
2760
+
2761
+ UPDATE tickets
2762
+ SET agent_status = 'error',
2763
+ agent_log = 'Legacy check repair causal provenance could not be recovered',
2764
+ streaming_response = NULL, updated_at = CURRENT_TIMESTAMP
2765
+ WHERE agent_status = 'running' AND EXISTS (
2766
+ SELECT 1 FROM check_repair_unrecoverable_children_migration child
2767
+ WHERE child.project_id = tickets.project_id AND child.ticket_id = tickets.id
2768
+ );
2769
+
2770
+ UPDATE execution_runs
2771
+ SET status = 'interrupted', domain_status = 'interrupted',
2772
+ failure_code = 'legacy_repair_provenance_unavailable',
2773
+ failure_message = 'Legacy check repair causal provenance could not be recovered',
2774
+ completed_at = COALESCE(completed_at, CURRENT_TIMESTAMP), updated_at = CURRENT_TIMESTAMP
2775
+ WHERE kind = 'check_repair' AND status IN ('queued', 'running', 'waiting')
2776
+ AND id IN (
2777
+ SELECT repair_run_id FROM check_repair_unrecoverable_migration
2778
+ );
2779
+
2780
+ DROP TABLE check_repair_details_legacy;
2781
+
2782
+ CREATE TABLE check_repair_diagnostic_provenance (
2783
+ check_repair_run_id TEXT NOT NULL,
2784
+ ordinal INTEGER NOT NULL,
2785
+ diagnostic_id TEXT NOT NULL,
2786
+ attempt_run_id TEXT NOT NULL,
2787
+ definition_id TEXT NOT NULL,
2788
+ PRIMARY KEY (check_repair_run_id, ordinal),
2789
+ UNIQUE (check_repair_run_id, diagnostic_id),
2790
+ FOREIGN KEY (check_repair_run_id) REFERENCES check_repair_details(execution_run_id) ON DELETE CASCADE,
2791
+ FOREIGN KEY (attempt_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2792
+ CHECK (ordinal >= 0)
2793
+ );
2794
+ CREATE TABLE check_repair_raw_output_provenance (
2795
+ check_repair_run_id TEXT NOT NULL,
2796
+ ordinal INTEGER NOT NULL,
2797
+ attempt_run_id TEXT NOT NULL,
2798
+ definition_id TEXT NOT NULL,
2799
+ PRIMARY KEY (check_repair_run_id, ordinal),
2800
+ UNIQUE (check_repair_run_id, attempt_run_id),
2801
+ FOREIGN KEY (check_repair_run_id) REFERENCES check_repair_details(execution_run_id) ON DELETE CASCADE,
2802
+ FOREIGN KEY (attempt_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2803
+ CHECK (ordinal >= 0)
2804
+ );
2805
+ INSERT INTO check_repair_diagnostic_provenance
2806
+ SELECT migration.* FROM check_repair_diagnostic_provenance_migration migration
2807
+ JOIN check_repair_details repair ON repair.execution_run_id = migration.check_repair_run_id;
2808
+ INSERT INTO check_repair_raw_output_provenance
2809
+ SELECT migration.* FROM check_repair_raw_output_provenance_migration migration
2810
+ JOIN check_repair_details repair ON repair.execution_run_id = migration.check_repair_run_id;
2811
+ DROP TABLE check_repair_diagnostic_provenance_migration;
2812
+ DROP TABLE check_repair_raw_output_provenance_migration;
2813
+ DROP TABLE check_repair_causal_migration;
2814
+ DROP TABLE check_repair_unrecoverable_children_migration;
2815
+ DROP TABLE check_repair_unrecoverable_migration;
2816
+ `);
2817
+ })();
2818
+ }
2819
+ db.exec(`
2508
2820
 
2509
2821
  CREATE TABLE IF NOT EXISTS check_repair_diagnostic_provenance (
2510
2822
  check_repair_run_id TEXT NOT NULL,
@@ -2532,7 +2844,8 @@ db.exec(`
2532
2844
  );
2533
2845
 
2534
2846
  CREATE TRIGGER IF NOT EXISTS preserve_check_repair_provenance
2535
- BEFORE UPDATE OF execution_run_id, source_batch_run_id, target_kind, target_bundle_id, ticket_id,
2847
+ BEFORE UPDATE OF execution_run_id, source_batch_run_id, target_kind, target_bundle_id,
2848
+ owner_type, owner_id, ticket_id, causal_execution_run_id, causal_agent_run_id,
2536
2849
  automation_progression_run_id, automation_boundary_purpose, initial_workspace_identity_json,
2537
2850
  configuration_fingerprint, effective_policy_fingerprint, definition_ids_json,
2538
2851
  retry_of_check_repair_run_id, created_at
@@ -2574,19 +2887,30 @@ db.exec(`
2574
2887
  FROM execution_runs repair
2575
2888
  JOIN execution_runs source ON source.id = NEW.source_batch_run_id AND source.project_id = repair.project_id
2576
2889
  JOIN check_batch_details source_details ON source_details.execution_run_id = source.id
2577
- JOIN tickets ticket ON ticket.id = NEW.ticket_id AND ticket.project_id = repair.project_id
2890
+ JOIN execution_runs causal ON causal.id = NEW.causal_execution_run_id AND causal.project_id = repair.project_id
2891
+ JOIN agent_runs causal_agent ON causal_agent.id = NEW.causal_agent_run_id
2892
+ AND causal_agent.execution_run_id = causal.id
2578
2893
  WHERE repair.id = NEW.execution_run_id AND repair.kind = 'check_repair'
2579
- AND NEW.target_kind = 'bundle' AND NEW.target_bundle_id IS NOT NULL
2894
+ AND ((NEW.target_kind = 'bundle' AND NEW.target_bundle_id IS NOT NULL)
2895
+ OR (NEW.target_kind = 'repo_root' AND NEW.target_bundle_id IS NULL))
2580
2896
  AND source.kind = 'check_batch' AND source.status = 'failed'
2581
2897
  AND source_details.target_kind = NEW.target_kind
2582
2898
  AND source_details.target_bundle_id IS NEW.target_bundle_id
2583
2899
  AND source_details.automation_boundary_purpose IS NEW.automation_boundary_purpose
2900
+ AND causal.kind IN ('build', 'build_follow_up', 'chat_turn')
2901
+ AND ((NEW.owner_type = 'ticket' AND NEW.ticket_id = NEW.owner_id AND causal.kind IN ('build', 'build_follow_up')
2902
+ AND EXISTS (SELECT 1 FROM tickets owner WHERE owner.id = NEW.owner_id AND owner.project_id = repair.project_id
2903
+ AND owner.worktree_bundle_id = NEW.target_bundle_id))
2904
+ OR (NEW.owner_type = 'chat_session' AND NEW.ticket_id IS NULL AND causal.kind = 'chat_turn'
2905
+ AND EXISTS (SELECT 1 FROM chat_sessions owner WHERE owner.id = NEW.owner_id AND owner.project_id = repair.project_id
2906
+ AND owner.mode = 'build' AND owner.target_kind = NEW.target_kind
2907
+ AND owner.target_bundle_id IS NEW.target_bundle_id)))
2584
2908
  AND (NEW.follow_up_run_id IS NULL OR EXISTS (
2585
2909
  SELECT 1 FROM execution_runs follow_up
2586
2910
  WHERE follow_up.id = NEW.follow_up_run_id AND follow_up.project_id = repair.project_id
2587
- AND follow_up.kind = 'build_follow_up' AND follow_up.parent_run_id = repair.id
2911
+ AND follow_up.kind = CASE NEW.owner_type WHEN 'ticket' THEN 'build_follow_up' ELSE 'chat_turn' END
2912
+ AND follow_up.parent_run_id = repair.id
2588
2913
  ))
2589
- AND ticket.worktree_bundle_id = NEW.target_bundle_id
2590
2914
  AND (NEW.retry_of_check_repair_run_id IS NULL OR EXISTS (
2591
2915
  SELECT 1 FROM execution_runs retry_source
2592
2916
  WHERE retry_source.id = NEW.retry_of_check_repair_run_id
@@ -2668,7 +2992,8 @@ db.exec(`
2668
2992
  JOIN execution_runs follow_up ON follow_up.id = NEW.follow_up_run_id
2669
2993
  AND follow_up.project_id = repair.project_id
2670
2994
  WHERE repair.id = OLD.execution_run_id AND repair.kind = 'check_repair'
2671
- AND follow_up.kind = 'build_follow_up' AND follow_up.parent_run_id = repair.id
2995
+ AND follow_up.kind = CASE OLD.owner_type WHEN 'ticket' THEN 'build_follow_up' ELSE 'chat_turn' END
2996
+ AND follow_up.parent_run_id = repair.id
2672
2997
  )
2673
2998
  )
2674
2999
  BEGIN
@@ -2709,6 +3034,97 @@ db.exec(`
2709
3034
  END;
2710
3035
  `);
2711
3036
  db.exec(`
3037
+
3038
+ CREATE TABLE IF NOT EXISTS check_auto_fix_loops (
3039
+ execution_run_id TEXT PRIMARY KEY,
3040
+ project_id TEXT NOT NULL,
3041
+ originating_batch_run_id TEXT NOT NULL UNIQUE,
3042
+ target_kind TEXT NOT NULL,
3043
+ target_bundle_id TEXT,
3044
+ owner_type TEXT NOT NULL,
3045
+ owner_id TEXT NOT NULL,
3046
+ causal_execution_run_id TEXT NOT NULL,
3047
+ causal_agent_run_id TEXT NOT NULL,
3048
+ automation_progression_run_id TEXT,
3049
+ automation_boundary_purpose TEXT,
3050
+ selected_definitions_json TEXT NOT NULL,
3051
+ auto_fix_definition_ids_json TEXT NOT NULL,
3052
+ definition_fingerprint TEXT NOT NULL,
3053
+ owner_config_json TEXT NOT NULL,
3054
+ initial_workspace_identity_json TEXT NOT NULL,
3055
+ cancellation_requested INTEGER NOT NULL DEFAULT 0,
3056
+ attempt_count INTEGER NOT NULL DEFAULT 0,
3057
+ final_batch_run_id TEXT,
3058
+ terminal_reason TEXT,
3059
+ terminal_message TEXT,
3060
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
3061
+ updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
3062
+ FOREIGN KEY (execution_run_id) REFERENCES execution_runs(id) ON DELETE CASCADE,
3063
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
3064
+ FOREIGN KEY (originating_batch_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
3065
+ FOREIGN KEY (causal_execution_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
3066
+ FOREIGN KEY (causal_agent_run_id) REFERENCES agent_runs(id) ON DELETE RESTRICT,
3067
+ FOREIGN KEY (automation_progression_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
3068
+ FOREIGN KEY (final_batch_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
3069
+ CHECK (target_kind IN ('repo_root', 'bundle')),
3070
+ CHECK ((target_kind = 'repo_root' AND target_bundle_id IS NULL)
3071
+ OR (target_kind = 'bundle' AND target_bundle_id IS NOT NULL)),
3072
+ CHECK (owner_type IN ('ticket', 'chat_session')),
3073
+ CHECK (length(definition_fingerprint) = 64),
3074
+ CHECK (cancellation_requested IN (0, 1)),
3075
+ CHECK (attempt_count BETWEEN 0 AND 3),
3076
+ CHECK (terminal_reason IS NULL OR terminal_reason IN (
3077
+ 'passed', 'ineligible', 'non_auto_fixable_only', 'agent_failure',
3078
+ 'no_workspace_changes', 'unchanged_failures', 'user_cancelled',
3079
+ 'stale', 'exhausted', 'interrupted'
3080
+ ))
3081
+ );
3082
+
3083
+ CREATE TABLE IF NOT EXISTS check_auto_fix_attempts (
3084
+ loop_run_id TEXT NOT NULL,
3085
+ ordinal INTEGER NOT NULL,
3086
+ source_batch_run_id TEXT NOT NULL,
3087
+ enabled_failure_signature TEXT NOT NULL,
3088
+ workspace_before_json TEXT NOT NULL,
3089
+ child_run_id TEXT,
3090
+ launch_outcome TEXT,
3091
+ rerun_batch_run_id TEXT,
3092
+ workspace_after_json TEXT,
3093
+ terminal_reason TEXT,
3094
+ terminal_message TEXT,
3095
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
3096
+ updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
3097
+ PRIMARY KEY (loop_run_id, ordinal),
3098
+ FOREIGN KEY (loop_run_id) REFERENCES check_auto_fix_loops(execution_run_id) ON DELETE CASCADE,
3099
+ FOREIGN KEY (source_batch_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
3100
+ FOREIGN KEY (child_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
3101
+ FOREIGN KEY (rerun_batch_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
3102
+ CHECK (ordinal BETWEEN 1 AND 3),
3103
+ CHECK (length(enabled_failure_signature) = 64),
3104
+ CHECK (launch_outcome IS NULL OR launch_outcome IN ('continued', 'fresh', 'rejected', 'completed', 'failed', 'cancelled'))
3105
+ );
3106
+
3107
+ CREATE TRIGGER IF NOT EXISTS preserve_check_auto_fix_loop_snapshot
3108
+ BEFORE UPDATE OF execution_run_id, originating_batch_run_id, target_kind, target_bundle_id,
3109
+ owner_type, owner_id, causal_execution_run_id, causal_agent_run_id,
3110
+ automation_progression_run_id, automation_boundary_purpose, selected_definitions_json,
3111
+ auto_fix_definition_ids_json, definition_fingerprint, owner_config_json,
3112
+ initial_workspace_identity_json, created_at ON check_auto_fix_loops
3113
+ BEGIN
3114
+ SELECT RAISE(ABORT, 'Check auto-fix loop snapshot is immutable');
3115
+ END;
3116
+
3117
+ CREATE TRIGGER IF NOT EXISTS preserve_check_auto_fix_attempt_snapshot
3118
+ BEFORE UPDATE OF loop_run_id, ordinal, source_batch_run_id, enabled_failure_signature,
3119
+ workspace_before_json, created_at ON check_auto_fix_attempts
3120
+ BEGIN
3121
+ SELECT RAISE(ABORT, 'Check auto-fix attempt snapshot is immutable');
3122
+ END;
3123
+
3124
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_check_auto_fix_active_target
3125
+ ON check_auto_fix_loops(target_kind, COALESCE(target_bundle_id, ''))
3126
+ WHERE terminal_reason IS NULL;
3127
+
2712
3128
  CREATE TABLE IF NOT EXISTS check_gate_evaluations (
2713
3129
  id TEXT PRIMARY KEY,
2714
3130
  project_id TEXT NOT NULL,
@@ -2831,6 +3247,23 @@ db.exec(`
2831
3247
  SELECT RAISE(ABORT, 'Invalid check gate evaluation attempt lineage');
2832
3248
  END;
2833
3249
  `);
3250
+ ensureColumn('check_auto_fix_loops', 'project_id', 'TEXT');
3251
+ db.exec(`
3252
+ UPDATE check_auto_fix_loops
3253
+ SET project_id = (
3254
+ SELECT project_id FROM execution_runs WHERE execution_runs.id = check_auto_fix_loops.execution_run_id
3255
+ )
3256
+ WHERE project_id IS NULL;
3257
+ DROP INDEX IF EXISTS idx_check_auto_fix_active_target;
3258
+ CREATE UNIQUE INDEX idx_check_auto_fix_active_target
3259
+ ON check_auto_fix_loops(project_id, target_kind, COALESCE(target_bundle_id, ''))
3260
+ WHERE terminal_reason IS NULL;
3261
+ CREATE TRIGGER IF NOT EXISTS preserve_check_auto_fix_loop_project
3262
+ BEFORE UPDATE OF project_id ON check_auto_fix_loops
3263
+ BEGIN
3264
+ SELECT RAISE(ABORT, 'Check auto-fix loop project is immutable');
3265
+ END;
3266
+ `);
2834
3267
  ensureColumn('check_gate_evaluations', 'expected_attempt_count', 'INTEGER NOT NULL DEFAULT 0');
2835
3268
  ensureColumn('check_gate_evaluations', 'attempts_sealed', 'INTEGER NOT NULL DEFAULT 1');
2836
3269
  db.exec(`
@@ -2879,6 +3312,13 @@ db.exec(`
2879
3312
  AND (
2880
3313
  (batch.initiated_by <> 'automation' AND batch.parent_run_id IS NULL)
2881
3314
  OR (batch.initiated_by = 'automation' AND batch.parent_run_id = NEW.automation_progression_run_id)
3315
+ OR (batch.initiated_by = 'automation' AND EXISTS (
3316
+ SELECT 1
3317
+ FROM check_auto_fix_loops loop
3318
+ WHERE loop.final_batch_run_id = batch.id
3319
+ AND loop.automation_progression_run_id = NEW.automation_progression_run_id
3320
+ AND loop.terminal_reason IS NOT NULL
3321
+ ))
2882
3322
  )
2883
3323
  )
2884
3324
  )
@@ -3016,32 +3456,46 @@ db.exec(`
3016
3456
  OR (NEW.target_kind = 'repo_root' AND NEW.target_bundle_id IS NULL
3017
3457
  AND bundle.kind = 'project_root')
3018
3458
  )
3019
- AND NOT EXISTS (
3020
- SELECT 1 FROM execution_runs sibling
3459
+ AND NOT EXISTS (
3460
+ SELECT 1 FROM execution_runs sibling
3021
3461
  WHERE sibling.project_id = run.project_id
3022
3462
  AND sibling.parent_run_id = progression.id
3023
3463
  AND sibling.id <> run.id
3024
- AND sibling.kind IN ('check_batch', 'check_repair', 'review', 'automation_review_fix', 'automation_commit', 'automation_push', 'automation_pull_request')
3025
- AND sibling.status IN ('queued', 'running', 'waiting')
3026
- AND NOT (
3027
- sibling.kind = 'check_repair'
3028
- AND NEW.rerun_of_batch_run_id IS NOT NULL
3029
- AND EXISTS (
3030
- SELECT 1 FROM check_repair_details repair_details
3031
- WHERE repair_details.execution_run_id = sibling.id
3032
- AND repair_details.source_batch_run_id = NEW.rerun_of_batch_run_id
3033
- AND repair_details.terminal_result IS NULL
3034
- AND repair_details.automation_progression_run_id = progression.id
3035
- AND repair_details.automation_boundary_purpose = NEW.automation_boundary_purpose
3036
- AND repair_details.target_kind = NEW.target_kind
3037
- AND repair_details.target_bundle_id IS NEW.target_bundle_id
3038
- )
3039
- )
3040
- )
3464
+ AND sibling.kind IN ('check_batch', 'check_repair', 'review', 'automation_review_fix', 'automation_commit', 'automation_push', 'automation_pull_request')
3465
+ AND sibling.status IN ('queued', 'running', 'waiting')
3466
+ AND NOT (
3467
+ sibling.kind = 'check_repair'
3468
+ AND NEW.rerun_of_batch_run_id IS NOT NULL
3469
+ AND EXISTS (
3470
+ SELECT 1 FROM check_repair_details repair_details
3471
+ WHERE repair_details.execution_run_id = sibling.id
3472
+ AND repair_details.source_batch_run_id = NEW.rerun_of_batch_run_id
3473
+ AND repair_details.terminal_result IS NULL
3474
+ AND repair_details.automation_progression_run_id = progression.id
3475
+ AND repair_details.automation_boundary_purpose = NEW.automation_boundary_purpose
3476
+ AND repair_details.target_kind = NEW.target_kind
3477
+ AND repair_details.target_bundle_id IS NEW.target_bundle_id
3478
+ )
3479
+ )
3480
+ )
3481
+ )
3482
+ )
3483
+ OR (
3484
+ run.initiated_by = 'automation'
3485
+ AND NEW.purpose = 'auto_fix'
3486
+ AND NEW.rerun_of_batch_run_id IS NOT NULL
3487
+ AND EXISTS (
3488
+ SELECT 1 FROM check_auto_fix_loops loop
3489
+ WHERE loop.execution_run_id = run.parent_run_id
3490
+ AND loop.originating_batch_run_id = NEW.causal_source_run_id
3491
+ AND loop.final_batch_run_id = NEW.rerun_of_batch_run_id
3492
+ AND loop.target_kind = NEW.target_kind
3493
+ AND loop.target_bundle_id IS NEW.target_bundle_id
3494
+ AND loop.terminal_reason IS NULL
3041
3495
  )
3496
+ )
3042
3497
  )
3043
3498
  AND (run.initiated_by = 'automation' OR NEW.automation_boundary_purpose IS NULL)
3044
- )
3045
3499
  ) OR (
3046
3500
  NEW.rerun_of_batch_run_id IS NOT NULL AND NOT EXISTS (
3047
3501
  SELECT 1 FROM execution_runs source, execution_runs current