@straiffi/archon 1.7.10 → 1.8.0

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 (152) hide show
  1. package/dist/client/assets/{ActivityView-IUWr92uj.js → ActivityView-EVy76nes.js} +1 -1
  2. package/dist/client/assets/{GitHubActionsDialog-0YtWvbFk.js → GitHubActionsDialog-D53aA0Fv.js} +1 -1
  3. package/dist/client/assets/VerificationDialog-Dm5DcY8F.js +4 -0
  4. package/dist/client/assets/{architectureDiagram-3BPJPVTR-LLMyOR-6.js → architectureDiagram-3BPJPVTR-CmMRkze6.js} +1 -1
  5. package/dist/client/assets/{blockDiagram-GPEHLZMM-aa1HitBJ.js → blockDiagram-GPEHLZMM-BgLsRgxM.js} +1 -1
  6. package/dist/client/assets/{c4Diagram-AAUBKEIU-BpSt5sdj.js → c4Diagram-AAUBKEIU-C3WJl13c.js} +1 -1
  7. package/dist/client/assets/channel-xqaERdN6.js +1 -0
  8. package/dist/client/assets/{chunk-2J33WTMH-D8pf3RNr.js → chunk-2J33WTMH-BfH4_PkQ.js} +1 -1
  9. package/dist/client/assets/{chunk-3OPIFGDE-_yx1N2iT.js → chunk-3OPIFGDE-CkVGPLM4.js} +1 -1
  10. package/dist/client/assets/{chunk-5ZQYHXKU-CYURGSbL.js → chunk-5ZQYHXKU-CDTwT753.js} +1 -1
  11. package/dist/client/assets/{chunk-727SXJPM-Ci2Mu1zz.js → chunk-727SXJPM-CKEhBrr_.js} +1 -1
  12. package/dist/client/assets/{chunk-AQP2D5EJ-CqVgrKze.js → chunk-AQP2D5EJ-D5QPK_k7.js} +1 -1
  13. package/dist/client/assets/{chunk-CSCIHK7Q-CT8aPk-o.js → chunk-CSCIHK7Q-BU4Ysr_2.js} +1 -1
  14. package/dist/client/assets/{chunk-KSCS5N6A-yM1i0J-p.js → chunk-KSCS5N6A-B9lHLGg1.js} +1 -1
  15. package/dist/client/assets/{chunk-L5ZTLDWV-BKMGr31Z.js → chunk-L5ZTLDWV-BrNsmxtD.js} +1 -1
  16. package/dist/client/assets/{chunk-LZXEDZCA-A7oUDETP.js → chunk-LZXEDZCA-CVgZc1nv.js} +2 -2
  17. package/dist/client/assets/{chunk-ND2GUHAM-Cagc-XAG.js → chunk-ND2GUHAM-DWWdi42a.js} +1 -1
  18. package/dist/client/assets/{chunk-NZK2D7GU-pe8tKLWI.js → chunk-NZK2D7GU-46-aRMvO.js} +1 -1
  19. package/dist/client/assets/{chunk-O5CBEL6O-BahwghWW.js → chunk-O5CBEL6O-BW6wHmzD.js} +1 -1
  20. package/dist/client/assets/{chunk-WU5MYG2G-BfSAFufr.js → chunk-WU5MYG2G-Wfk15Qtf.js} +1 -1
  21. package/dist/client/assets/classDiagram-4FO5ZUOK-BdwFrsZE.js +1 -0
  22. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DxAuXA1L.js +1 -0
  23. package/dist/client/assets/{dagre-BM42HDAG-DCma6-hS.js → dagre-BM42HDAG-CZ_BDahz.js} +1 -1
  24. package/dist/client/assets/{diagram-2AECGRRQ-DUeggZrO.js → diagram-2AECGRRQ-CQKXQvjO.js} +1 -1
  25. package/dist/client/assets/{diagram-5GNKFQAL-CdjOKGtl.js → diagram-5GNKFQAL-Dgsh82oA.js} +1 -1
  26. package/dist/client/assets/{diagram-KO2AKTUF-CYjXhgh_.js → diagram-KO2AKTUF-DUwmm3sV.js} +1 -1
  27. package/dist/client/assets/{diagram-LMA3HP47-DYBCh4cm.js → diagram-LMA3HP47-DLGz0g10.js} +1 -1
  28. package/dist/client/assets/{diagram-OG6HWLK6-D3HPQt3z.js → diagram-OG6HWLK6-CjS6v8Zz.js} +1 -1
  29. package/dist/client/assets/{erDiagram-TEJ5UH35-mG8Yztg-.js → erDiagram-TEJ5UH35-DHaCFHn9.js} +1 -1
  30. package/dist/client/assets/{flowDiagram-I6XJVG4X-4FvjuoSZ.js → flowDiagram-I6XJVG4X-E4LSVqs6.js} +1 -1
  31. package/dist/client/assets/{ganttDiagram-6RSMTGT7-ByCQI8ft.js → ganttDiagram-6RSMTGT7-BWywa_xn.js} +1 -1
  32. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-CzEUA7nB.js → gitGraphDiagram-PVQCEYII-BK4kWKuB.js} +1 -1
  33. package/dist/client/assets/index-CS2arNNP.js +274 -0
  34. package/dist/client/assets/index-Cb_ZVYaw.css +2 -0
  35. package/dist/client/assets/{infoDiagram-5YYISTIA-Q9CqnXO1.js → infoDiagram-5YYISTIA-BX7HzDWX.js} +1 -1
  36. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CO8BToGf.js → ishikawaDiagram-YF4QCWOH-CEnWCNes.js} +1 -1
  37. package/dist/client/assets/{journeyDiagram-JHISSGLW-DtOyWvDJ.js → journeyDiagram-JHISSGLW-MQPDgPxD.js} +1 -1
  38. package/dist/client/assets/{kanban-definition-UN3LZRKU-DIn9bYpk.js → kanban-definition-UN3LZRKU-PwVLKAnN.js} +1 -1
  39. package/dist/client/assets/{line-H-k0M9_s.js → line-BJMnG1sl.js} +1 -1
  40. package/dist/client/assets/{mermaid-parser.core-CZOUS5zK.js → mermaid-parser.core-Bwv8qN83.js} +1 -1
  41. package/dist/client/assets/{mermaid.core-Ck71Qr7h.js → mermaid.core-DpFOXZmb.js} +3 -3
  42. package/dist/client/assets/{mindmap-definition-RKZ34NQL-BRFEcJw_.js → mindmap-definition-RKZ34NQL-Dt-9JT_z.js} +1 -1
  43. package/dist/client/assets/{pieDiagram-4H26LBE5-CwihXXcJ.js → pieDiagram-4H26LBE5-aD3cg6m3.js} +1 -1
  44. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-moiRw4Cm.js → quadrantDiagram-W4KKPZXB-DUh4hgmW.js} +1 -1
  45. package/dist/client/assets/{requirementDiagram-4Y6WPE33-tshvM_vV.js → requirementDiagram-4Y6WPE33-DOgz-iLT.js} +1 -1
  46. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-rtKIuBEp.js → sankeyDiagram-5OEKKPKP-BqpDXW6-.js} +1 -1
  47. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-lkTCo4wE.js → sequenceDiagram-3UESZ5HK-BM0Gvqia.js} +1 -1
  48. package/dist/client/assets/{stateDiagram-AJRCARHV-CFQhVUSd.js → stateDiagram-AJRCARHV-XZMyDtEy.js} +1 -1
  49. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-C0Qe8FiL.js +1 -0
  50. package/dist/client/assets/{timeline-definition-PNZ67QCA-BmlQ7Wiy.js → timeline-definition-PNZ67QCA-gqiDwxVu.js} +1 -1
  51. package/dist/client/assets/{vennDiagram-CIIHVFJN-CZyZepcT.js → vennDiagram-CIIHVFJN-MxeqqqyG.js} +1 -1
  52. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-C2b52gni.js → wardleyDiagram-YWT4CUSO-pMgGO6cB.js} +1 -1
  53. package/dist/client/assets/{xychartDiagram-2RQKCTM6-FqnROUHq.js → xychartDiagram-2RQKCTM6-_VK_NZDn.js} +1 -1
  54. package/dist/client/index.html +2 -2
  55. package/dist/server/db.js +452 -7
  56. package/dist/server/db.js.map +1 -1
  57. package/dist/server/index.js +309 -195
  58. package/dist/server/index.js.map +1 -1
  59. package/dist/server/lib/activeAutomationChild.js +6 -1
  60. package/dist/server/lib/activeAutomationChild.js.map +1 -1
  61. package/dist/server/lib/automationCheckGate.js +183 -50
  62. package/dist/server/lib/automationCheckGate.js.map +1 -1
  63. package/dist/server/lib/automationProgression.js +76 -9
  64. package/dist/server/lib/automationProgression.js.map +1 -1
  65. package/dist/server/lib/automationReconciliation.js +65 -0
  66. package/dist/server/lib/automationReconciliation.js.map +1 -1
  67. package/dist/server/lib/automationResumeDecision.js +69 -32
  68. package/dist/server/lib/automationResumeDecision.js.map +1 -1
  69. package/dist/server/lib/automationReviewGate.js +6 -1
  70. package/dist/server/lib/automationReviewGate.js.map +1 -1
  71. package/dist/server/lib/bundleActivity.js +20 -0
  72. package/dist/server/lib/bundleActivity.js.map +1 -1
  73. package/dist/server/lib/bundleReviewOperations.js +36 -5
  74. package/dist/server/lib/bundleReviewOperations.js.map +1 -1
  75. package/dist/server/lib/chatTicketProposals.js +2 -1
  76. package/dist/server/lib/chatTicketProposals.js.map +1 -1
  77. package/dist/server/lib/checkDiagnosticParsers.js +301 -0
  78. package/dist/server/lib/checkDiagnosticParsers.js.map +1 -0
  79. package/dist/server/lib/checkDiagnostics.js +142 -0
  80. package/dist/server/lib/checkDiagnostics.js.map +1 -0
  81. package/dist/server/lib/checkGateEvaluations.js +89 -1
  82. package/dist/server/lib/checkGateEvaluations.js.map +1 -1
  83. package/dist/server/lib/checkRepair.js +1031 -0
  84. package/dist/server/lib/checkRepair.js.map +1 -0
  85. package/dist/server/lib/checkRepairLifecycle.js +56 -0
  86. package/dist/server/lib/checkRepairLifecycle.js.map +1 -0
  87. package/dist/server/lib/checkRepairReconciliation.js +145 -0
  88. package/dist/server/lib/checkRepairReconciliation.js.map +1 -0
  89. package/dist/server/lib/checkRunner.js +115 -21
  90. package/dist/server/lib/checkRunner.js.map +1 -1
  91. package/dist/server/lib/checkRuns.js +37 -3
  92. package/dist/server/lib/checkRuns.js.map +1 -1
  93. package/dist/server/lib/executionReconciliation.js +21 -11
  94. package/dist/server/lib/executionReconciliation.js.map +1 -1
  95. package/dist/server/lib/executionRetryPredicates.js +3 -1
  96. package/dist/server/lib/executionRetryPredicates.js.map +1 -1
  97. package/dist/server/lib/executionRunRetention.js +24 -3
  98. package/dist/server/lib/executionRunRetention.js.map +1 -1
  99. package/dist/server/lib/executionRuns.js +5 -2
  100. package/dist/server/lib/executionRuns.js.map +1 -1
  101. package/dist/server/lib/planModeQuestions.js +2 -0
  102. package/dist/server/lib/planModeQuestions.js.map +1 -1
  103. package/dist/server/lib/planQuestions.js +39 -7
  104. package/dist/server/lib/planQuestions.js.map +1 -1
  105. package/dist/server/lib/projectMemorySuggestions.js +2 -1
  106. package/dist/server/lib/projectMemorySuggestions.js.map +1 -1
  107. package/dist/server/lib/projects.js +1 -26
  108. package/dist/server/lib/projects.js.map +1 -1
  109. package/dist/server/lib/pullRequestContent.js +14 -0
  110. package/dist/server/lib/pullRequestContent.js.map +1 -1
  111. package/dist/server/lib/requiredCheckPolicy.js +13 -49
  112. package/dist/server/lib/requiredCheckPolicy.js.map +1 -1
  113. package/dist/server/lib/requiredCheckPolicyPrompt.js +46 -0
  114. package/dist/server/lib/requiredCheckPolicyPrompt.js.map +1 -0
  115. package/dist/server/lib/specDraft.js +6 -0
  116. package/dist/server/lib/specDraft.js.map +1 -1
  117. package/dist/server/lib/specResources.js +42 -0
  118. package/dist/server/lib/specResources.js.map +1 -0
  119. package/dist/server/lib/specs.js +9 -5
  120. package/dist/server/lib/specs.js.map +1 -1
  121. package/dist/server/lib/ticketAutomation.js +10 -3
  122. package/dist/server/lib/ticketAutomation.js.map +1 -1
  123. package/dist/server/lib/ticketAutomationCommit.js +36 -11
  124. package/dist/server/lib/ticketAutomationCommit.js.map +1 -1
  125. package/dist/server/lib/ticketFollowUpOperations.js +24 -9
  126. package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
  127. package/dist/server/lib/tickets.js +9 -32
  128. package/dist/server/lib/tickets.js.map +1 -1
  129. package/dist/server/lib/types.js +1 -0
  130. package/dist/server/lib/types.js.map +1 -1
  131. package/dist/server/workers/build.js +34 -12
  132. package/dist/server/workers/build.js.map +1 -1
  133. package/dist/server/workers/chat.js +4 -3
  134. package/dist/server/workers/chat.js.map +1 -1
  135. package/dist/server/workers/followUp.js +60 -17
  136. package/dist/server/workers/followUp.js.map +1 -1
  137. package/dist/server/workers/plan.js +5 -3
  138. package/dist/server/workers/plan.js.map +1 -1
  139. package/dist/server/workers/planFollowUp.js +5 -6
  140. package/dist/server/workers/planFollowUp.js.map +1 -1
  141. package/dist/server/workers/review.js +38 -6
  142. package/dist/server/workers/review.js.map +1 -1
  143. package/dist/server/workers/specSession.js +10 -4
  144. package/dist/server/workers/specSession.js.map +1 -1
  145. package/package.json +1 -1
  146. package/dist/client/assets/VerificationDialog-B4Pyz1LV.js +0 -4
  147. package/dist/client/assets/channel-DWPRC-jg.js +0 -1
  148. package/dist/client/assets/classDiagram-4FO5ZUOK-DBZaZLLc.js +0 -1
  149. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-B7HsVFoJ.js +0 -1
  150. package/dist/client/assets/index-D-miHTTb.js +0 -273
  151. package/dist/client/assets/index-TAQIlNdJ.css +0 -2
  152. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-rrN4DgWp.js +0 -1
package/dist/server/db.js CHANGED
@@ -132,6 +132,7 @@ ensureColumn('worktree_bundles', 'automation_depth', 'TEXT');
132
132
  ensureColumn('worktree_bundles', 'automation_review_fix_enabled', 'INTEGER');
133
133
  ensureColumn('worktree_bundles', 'automation_pause_on_open_questions', 'INTEGER');
134
134
  ensureColumn('worktree_bundles', 'required_check_policy_override', 'TEXT');
135
+ db.exec('UPDATE worktree_bundles SET required_check_policy_override = NULL WHERE required_check_policy_override IS NOT NULL');
135
136
  ensureColumn('projects', 'worktree_sync', 'TEXT');
136
137
  ensureColumn('projects', 'active_target_kind', "TEXT NOT NULL DEFAULT 'repo_root'");
137
138
  ensureColumn('projects', 'active_target_bundle_id', 'TEXT');
@@ -824,6 +825,7 @@ db.exec(`
824
825
  likely_files_json TEXT,
825
826
  tickets_json TEXT,
826
827
  dependencies_json TEXT,
828
+ resource_urls_json TEXT,
827
829
  mermaid TEXT,
828
830
  mockup TEXT,
829
831
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
@@ -833,6 +835,7 @@ db.exec(`
833
835
  ensureColumn('spec_snapshots', 'plan_text', 'TEXT');
834
836
  ensureColumn('spec_snapshots', 'mockup', 'TEXT');
835
837
  ensureColumn('spec_snapshots', 'file_relation_graph', 'TEXT');
838
+ ensureColumn('spec_snapshots', 'resource_urls_json', 'TEXT');
836
839
  db.exec(`
837
840
  CREATE TABLE IF NOT EXISTS spec_message_attachments (
838
841
  attachment_id TEXT PRIMARY KEY,
@@ -1812,6 +1815,7 @@ db.exec(`
1812
1815
  target_label TEXT,
1813
1816
  selected_definition_snapshots_json TEXT NOT NULL,
1814
1817
  initial_workspace_identity_json TEXT NOT NULL,
1818
+ final_workspace_identity_json TEXT,
1815
1819
  configuration_fingerprint TEXT NOT NULL,
1816
1820
  stop_requested INTEGER NOT NULL DEFAULT 0,
1817
1821
  queued_count INTEGER NOT NULL DEFAULT 0,
@@ -1837,6 +1841,7 @@ db.exec(`
1837
1841
  )
1838
1842
  `);
1839
1843
  ensureColumn('check_batch_details', 'automation_boundary_purpose', 'TEXT');
1844
+ ensureColumn('check_batch_details', 'final_workspace_identity_json', 'TEXT');
1840
1845
  db.exec(`
1841
1846
  CREATE TABLE IF NOT EXISTS check_attempt_details (
1842
1847
  execution_run_id TEXT PRIMARY KEY,
@@ -1862,13 +1867,420 @@ db.exec(`
1862
1867
  FOREIGN KEY (rerun_of_attempt_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
1863
1868
  CHECK (length(definition_id) BETWEEN 1 AND 500),
1864
1869
  CHECK (length(definition_fingerprint) = 64 AND definition_fingerprint NOT GLOB '*[^0-9a-f]*'),
1865
- CHECK (outcome IS NULL OR outcome IN ('passed', 'command_failure', 'spawn_failure', 'timeout',
1870
+ CHECK (outcome IS NULL OR outcome IN ('passed', 'command_failure', 'spawn_failure',
1871
+ 'infrastructure_failure', 'evidence_persistence_failure', 'timeout',
1866
1872
  'workspace_changed_before_start', 'user_stop', 'restart_loss', 'shutdown_loss')),
1867
1873
  CHECK (output_revision >= 0 AND retained_start_offset >= 0 AND retained_end_offset >= retained_start_offset
1868
1874
  AND total_persisted_bytes >= retained_end_offset),
1869
1875
  CHECK (output_retention_state IN ('retained', 'expired'))
1870
1876
  )
1871
1877
  `);
1878
+ ensureColumn('check_attempt_details', 'retained_end_offset', 'INTEGER NOT NULL DEFAULT 0');
1879
+ ensureColumn('check_attempt_details', 'retained_output', "TEXT NOT NULL DEFAULT ''");
1880
+ const checkAttemptSchema = db.prepare(`
1881
+ SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'check_attempt_details'
1882
+ `).get();
1883
+ if (checkAttemptSchema && !checkAttemptSchema.sql.includes('evidence_persistence_failure')) {
1884
+ db.transaction(() => {
1885
+ db.exec(`
1886
+ DROP TRIGGER IF EXISTS preserve_check_attempt_snapshots;
1887
+ DROP TRIGGER IF EXISTS preserve_completed_check_attempt_details;
1888
+ ALTER TABLE check_attempt_details RENAME TO check_attempt_details_legacy;
1889
+
1890
+ CREATE TABLE check_attempt_details (
1891
+ execution_run_id TEXT PRIMARY KEY,
1892
+ batch_run_id TEXT NOT NULL,
1893
+ definition_id TEXT NOT NULL,
1894
+ command_snapshot_json TEXT NOT NULL,
1895
+ definition_fingerprint TEXT NOT NULL,
1896
+ initial_workspace_identity_json TEXT NOT NULL,
1897
+ final_workspace_identity_json TEXT,
1898
+ outcome TEXT,
1899
+ rerun_of_attempt_run_id TEXT,
1900
+ exit_code INTEGER,
1901
+ exit_signal TEXT,
1902
+ exit_error TEXT,
1903
+ output_revision INTEGER NOT NULL DEFAULT 0,
1904
+ retained_start_offset INTEGER NOT NULL DEFAULT 0,
1905
+ retained_end_offset INTEGER NOT NULL DEFAULT 0,
1906
+ total_persisted_bytes INTEGER NOT NULL DEFAULT 0,
1907
+ retained_output TEXT NOT NULL DEFAULT '',
1908
+ output_retention_state TEXT NOT NULL DEFAULT 'retained',
1909
+ FOREIGN KEY (execution_run_id) REFERENCES execution_runs(id) ON DELETE CASCADE,
1910
+ FOREIGN KEY (batch_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
1911
+ FOREIGN KEY (rerun_of_attempt_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
1912
+ CHECK (length(definition_id) BETWEEN 1 AND 500),
1913
+ CHECK (length(definition_fingerprint) = 64 AND definition_fingerprint NOT GLOB '*[^0-9a-f]*'),
1914
+ CHECK (outcome IS NULL OR outcome IN ('passed', 'command_failure', 'spawn_failure',
1915
+ 'infrastructure_failure', 'evidence_persistence_failure', 'timeout',
1916
+ 'workspace_changed_before_start', 'user_stop', 'restart_loss', 'shutdown_loss')),
1917
+ CHECK (output_revision >= 0 AND retained_start_offset >= 0 AND retained_end_offset >= retained_start_offset
1918
+ AND total_persisted_bytes >= retained_end_offset),
1919
+ CHECK (output_retention_state IN ('retained', 'expired'))
1920
+ );
1921
+
1922
+ INSERT INTO check_attempt_details (
1923
+ execution_run_id, batch_run_id, definition_id, command_snapshot_json, definition_fingerprint,
1924
+ initial_workspace_identity_json, final_workspace_identity_json, outcome, rerun_of_attempt_run_id,
1925
+ exit_code, exit_signal, exit_error, output_revision, retained_start_offset, retained_end_offset,
1926
+ total_persisted_bytes, retained_output, output_retention_state
1927
+ )
1928
+ SELECT
1929
+ execution_run_id, batch_run_id, definition_id, command_snapshot_json, definition_fingerprint,
1930
+ initial_workspace_identity_json, final_workspace_identity_json, outcome, rerun_of_attempt_run_id,
1931
+ exit_code, exit_signal, exit_error, output_revision, retained_start_offset, retained_end_offset,
1932
+ total_persisted_bytes, retained_output, output_retention_state
1933
+ FROM check_attempt_details_legacy;
1934
+
1935
+ DROP TABLE check_attempt_details_legacy;
1936
+ `);
1937
+ })();
1938
+ }
1939
+ db.exec(`
1940
+ CREATE TABLE IF NOT EXISTS check_attempt_diagnostic_parsers (
1941
+ attempt_run_id TEXT PRIMARY KEY,
1942
+ definition_id TEXT NOT NULL,
1943
+ parser_kind TEXT NOT NULL DEFAULT 'none',
1944
+ parser_version TEXT,
1945
+ status TEXT NOT NULL DEFAULT 'pending',
1946
+ diagnostic_count INTEGER NOT NULL DEFAULT 0,
1947
+ truncated INTEGER NOT NULL DEFAULT 0,
1948
+ retention_state TEXT NOT NULL DEFAULT 'retained',
1949
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
1950
+ updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
1951
+ FOREIGN KEY (attempt_run_id) REFERENCES check_attempt_details(execution_run_id) ON DELETE CASCADE,
1952
+ CHECK (length(definition_id) BETWEEN 1 AND 500),
1953
+ CHECK (parser_kind IN ('typescript', 'eslint', 'none')),
1954
+ CHECK ((parser_kind = 'none' AND parser_version IS NULL) OR (parser_kind <> 'none' AND length(parser_version) BETWEEN 1 AND 32)),
1955
+ CHECK (status IN ('pending', 'complete', 'unsupported', 'malformed', 'interrupted')),
1956
+ CHECK (diagnostic_count BETWEEN 0 AND 500),
1957
+ CHECK (truncated IN (0, 1)),
1958
+ CHECK (retention_state IN ('retained', 'expired'))
1959
+ );
1960
+
1961
+ CREATE TABLE IF NOT EXISTS check_attempt_diagnostics (
1962
+ id TEXT PRIMARY KEY,
1963
+ attempt_run_id TEXT NOT NULL,
1964
+ definition_id TEXT NOT NULL,
1965
+ ordinal INTEGER NOT NULL,
1966
+ severity TEXT NOT NULL,
1967
+ message TEXT NOT NULL,
1968
+ code TEXT,
1969
+ file_path TEXT,
1970
+ start_line INTEGER,
1971
+ start_column INTEGER,
1972
+ end_line INTEGER,
1973
+ end_column INTEGER,
1974
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
1975
+ UNIQUE (attempt_run_id, ordinal),
1976
+ FOREIGN KEY (attempt_run_id) REFERENCES check_attempt_details(execution_run_id) ON DELETE CASCADE,
1977
+ CHECK (length(id) BETWEEN 1 AND 100),
1978
+ CHECK (length(definition_id) BETWEEN 1 AND 500),
1979
+ CHECK (severity IN ('error', 'warning', 'info', 'unknown')),
1980
+ CHECK (length(CAST(message AS BLOB)) BETWEEN 1 AND 16384),
1981
+ CHECK (code IS NULL OR length(CAST(code AS BLOB)) BETWEEN 1 AND 256),
1982
+ CHECK (file_path IS NULL OR length(CAST(file_path AS BLOB)) BETWEEN 1 AND 4096),
1983
+ CHECK ((file_path IS NULL AND start_line IS NULL AND start_column IS NULL AND end_line IS NULL AND end_column IS NULL)
1984
+ OR (file_path IS NOT NULL AND start_line >= 1 AND start_column >= 1
1985
+ AND ((end_line IS NULL AND end_column IS NULL)
1986
+ OR (end_line >= start_line AND end_column >= 1 AND (end_line > start_line OR end_column >= start_column))))),
1987
+ CHECK (ordinal BETWEEN 0 AND 499)
1988
+ );
1989
+
1990
+ CREATE TRIGGER IF NOT EXISTS validate_check_diagnostic_parser_insert
1991
+ BEFORE INSERT ON check_attempt_diagnostic_parsers
1992
+ WHEN NOT EXISTS (
1993
+ SELECT 1 FROM check_attempt_details attempt
1994
+ WHERE attempt.execution_run_id = NEW.attempt_run_id AND attempt.definition_id = NEW.definition_id
1995
+ )
1996
+ BEGIN
1997
+ SELECT RAISE(ABORT, 'Invalid check diagnostic parser ownership');
1998
+ END;
1999
+
2000
+ CREATE TRIGGER IF NOT EXISTS validate_check_diagnostic_insert
2001
+ BEFORE INSERT ON check_attempt_diagnostics
2002
+ WHEN NOT EXISTS (
2003
+ SELECT 1
2004
+ FROM check_attempt_diagnostic_parsers parser
2005
+ WHERE parser.attempt_run_id = NEW.attempt_run_id
2006
+ AND parser.definition_id = NEW.definition_id
2007
+ AND parser.status = 'pending'
2008
+ AND parser.retention_state = 'retained'
2009
+ )
2010
+ BEGIN
2011
+ SELECT RAISE(ABORT, 'Invalid check diagnostic ownership');
2012
+ END;
2013
+
2014
+ CREATE TRIGGER IF NOT EXISTS preserve_check_diagnostics
2015
+ BEFORE UPDATE ON check_attempt_diagnostics
2016
+ BEGIN
2017
+ SELECT RAISE(ABORT, 'Check diagnostics are immutable');
2018
+ END;
2019
+
2020
+ CREATE TRIGGER IF NOT EXISTS preserve_check_diagnostic_parser_ownership
2021
+ BEFORE UPDATE OF attempt_run_id, definition_id, created_at ON check_attempt_diagnostic_parsers
2022
+ BEGIN
2023
+ SELECT RAISE(ABORT, 'Check diagnostic parser ownership is immutable');
2024
+ END;
2025
+
2026
+ CREATE TRIGGER IF NOT EXISTS interrupt_incomplete_check_diagnostic_parser
2027
+ AFTER UPDATE OF outcome ON check_attempt_details
2028
+ WHEN NEW.outcome IS NOT NULL
2029
+ BEGIN
2030
+ UPDATE check_attempt_diagnostic_parsers
2031
+ SET status = 'interrupted', diagnostic_count = (
2032
+ SELECT COUNT(*) FROM check_attempt_diagnostics diagnostic
2033
+ WHERE diagnostic.attempt_run_id = NEW.execution_run_id
2034
+ ), updated_at = CURRENT_TIMESTAMP
2035
+ WHERE attempt_run_id = NEW.execution_run_id AND status = 'pending';
2036
+ END;
2037
+ `);
2038
+ db.exec(`
2039
+ CREATE TABLE IF NOT EXISTS check_repair_details (
2040
+ execution_run_id TEXT PRIMARY KEY,
2041
+ source_batch_run_id TEXT NOT NULL,
2042
+ target_kind TEXT NOT NULL,
2043
+ target_bundle_id TEXT,
2044
+ ticket_id TEXT NOT NULL,
2045
+ automation_progression_run_id TEXT,
2046
+ automation_boundary_purpose TEXT,
2047
+ initial_workspace_identity_json TEXT NOT NULL,
2048
+ configuration_fingerprint TEXT NOT NULL,
2049
+ effective_policy_fingerprint TEXT,
2050
+ definition_ids_json TEXT NOT NULL,
2051
+ follow_up_run_id TEXT,
2052
+ rerun_batch_run_id TEXT,
2053
+ terminal_result TEXT,
2054
+ terminal_message TEXT,
2055
+ retry_of_check_repair_run_id TEXT,
2056
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
2057
+ updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
2058
+ FOREIGN KEY (execution_run_id) REFERENCES execution_runs(id) ON DELETE CASCADE,
2059
+ FOREIGN KEY (source_batch_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2060
+ FOREIGN KEY (automation_progression_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2061
+ FOREIGN KEY (follow_up_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2062
+ FOREIGN KEY (rerun_batch_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2063
+ FOREIGN KEY (retry_of_check_repair_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2064
+ CHECK (target_kind IN ('repo_root', 'bundle')),
2065
+ CHECK ((target_kind = 'repo_root' AND target_bundle_id IS NULL)
2066
+ OR (target_kind = 'bundle' AND target_bundle_id IS NOT NULL AND length(trim(target_bundle_id)) > 0)),
2067
+ CHECK (length(configuration_fingerprint) = 64 AND configuration_fingerprint NOT GLOB '*[^0-9a-f]*'),
2068
+ CHECK (effective_policy_fingerprint IS NULL OR (
2069
+ length(effective_policy_fingerprint) = 64 AND effective_policy_fingerprint NOT GLOB '*[^0-9a-f]*'
2070
+ )),
2071
+ CHECK (automation_boundary_purpose IS NULL OR automation_boundary_purpose IN (
2072
+ 'automation_review', 'automation_commit', 'automation_push', 'automation_pull_request'
2073
+ )),
2074
+ CHECK ((automation_progression_run_id IS NULL AND automation_boundary_purpose IS NULL)
2075
+ OR (automation_progression_run_id IS NOT NULL AND automation_boundary_purpose IS NOT NULL)),
2076
+ CHECK ((automation_progression_run_id IS NULL AND effective_policy_fingerprint IS NULL)
2077
+ OR (automation_progression_run_id IS NOT NULL AND effective_policy_fingerprint IS NOT NULL)),
2078
+ CHECK (terminal_result IS NULL OR terminal_result IN ('passed', 'failed', 'cancelled', 'interrupted')),
2079
+ CHECK (terminal_message IS NULL OR length(CAST(terminal_message AS BLOB)) <= 16384)
2080
+ );
2081
+
2082
+ CREATE TABLE IF NOT EXISTS check_repair_diagnostic_provenance (
2083
+ check_repair_run_id TEXT NOT NULL,
2084
+ ordinal INTEGER NOT NULL,
2085
+ diagnostic_id TEXT NOT NULL,
2086
+ attempt_run_id TEXT NOT NULL,
2087
+ definition_id TEXT NOT NULL,
2088
+ PRIMARY KEY (check_repair_run_id, ordinal),
2089
+ UNIQUE (check_repair_run_id, diagnostic_id),
2090
+ FOREIGN KEY (check_repair_run_id) REFERENCES check_repair_details(execution_run_id) ON DELETE CASCADE,
2091
+ FOREIGN KEY (attempt_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2092
+ CHECK (ordinal >= 0)
2093
+ );
2094
+
2095
+ CREATE TABLE IF NOT EXISTS check_repair_raw_output_provenance (
2096
+ check_repair_run_id TEXT NOT NULL,
2097
+ ordinal INTEGER NOT NULL,
2098
+ attempt_run_id TEXT NOT NULL,
2099
+ definition_id TEXT NOT NULL,
2100
+ PRIMARY KEY (check_repair_run_id, ordinal),
2101
+ UNIQUE (check_repair_run_id, attempt_run_id),
2102
+ FOREIGN KEY (check_repair_run_id) REFERENCES check_repair_details(execution_run_id) ON DELETE CASCADE,
2103
+ FOREIGN KEY (attempt_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
2104
+ CHECK (ordinal >= 0)
2105
+ );
2106
+
2107
+ CREATE TRIGGER IF NOT EXISTS preserve_check_repair_provenance
2108
+ BEFORE UPDATE OF execution_run_id, source_batch_run_id, target_kind, target_bundle_id, ticket_id,
2109
+ automation_progression_run_id, automation_boundary_purpose, initial_workspace_identity_json,
2110
+ configuration_fingerprint, effective_policy_fingerprint, definition_ids_json,
2111
+ retry_of_check_repair_run_id, created_at
2112
+ ON check_repair_details
2113
+ BEGIN
2114
+ SELECT RAISE(ABORT, 'Check repair provenance is immutable');
2115
+ END;
2116
+
2117
+ CREATE TRIGGER IF NOT EXISTS preserve_check_repair_diagnostic_provenance
2118
+ BEFORE UPDATE ON check_repair_diagnostic_provenance
2119
+ BEGIN
2120
+ SELECT RAISE(ABORT, 'Check repair diagnostic provenance is immutable');
2121
+ END;
2122
+
2123
+ CREATE TRIGGER IF NOT EXISTS preserve_check_repair_raw_output_provenance
2124
+ BEFORE UPDATE ON check_repair_raw_output_provenance
2125
+ BEGIN
2126
+ SELECT RAISE(ABORT, 'Check repair raw output provenance is immutable');
2127
+ END;
2128
+
2129
+ CREATE TRIGGER IF NOT EXISTS prevent_check_repair_raw_output_provenance_delete
2130
+ BEFORE DELETE ON check_repair_raw_output_provenance
2131
+ WHEN EXISTS (
2132
+ SELECT 1
2133
+ FROM check_repair_details repair
2134
+ JOIN execution_runs repair_run ON repair_run.id = repair.execution_run_id
2135
+ JOIN projects project ON project.id = repair_run.project_id
2136
+ WHERE repair.execution_run_id = OLD.check_repair_run_id
2137
+ AND project.deletion_started_at IS NULL
2138
+ )
2139
+ BEGIN
2140
+ SELECT RAISE(ABORT, 'Check repair raw output provenance is immutable');
2141
+ END;
2142
+
2143
+ CREATE TRIGGER IF NOT EXISTS validate_check_repair_details_insert
2144
+ BEFORE INSERT ON check_repair_details
2145
+ WHEN NOT EXISTS (
2146
+ SELECT 1
2147
+ FROM execution_runs repair
2148
+ JOIN execution_runs source ON source.id = NEW.source_batch_run_id AND source.project_id = repair.project_id
2149
+ JOIN check_batch_details source_details ON source_details.execution_run_id = source.id
2150
+ JOIN tickets ticket ON ticket.id = NEW.ticket_id AND ticket.project_id = repair.project_id
2151
+ WHERE repair.id = NEW.execution_run_id AND repair.kind = 'check_repair'
2152
+ AND NEW.target_kind = 'bundle' AND NEW.target_bundle_id IS NOT NULL
2153
+ AND source.kind = 'check_batch' AND source.status = 'failed'
2154
+ AND source_details.target_kind = NEW.target_kind
2155
+ AND source_details.target_bundle_id IS NEW.target_bundle_id
2156
+ AND source_details.automation_boundary_purpose IS NEW.automation_boundary_purpose
2157
+ AND (NEW.follow_up_run_id IS NULL OR EXISTS (
2158
+ SELECT 1 FROM execution_runs follow_up
2159
+ WHERE follow_up.id = NEW.follow_up_run_id AND follow_up.project_id = repair.project_id
2160
+ AND follow_up.kind = 'build_follow_up' AND follow_up.parent_run_id = repair.id
2161
+ ))
2162
+ AND ticket.worktree_bundle_id = NEW.target_bundle_id
2163
+ AND (NEW.retry_of_check_repair_run_id IS NULL OR EXISTS (
2164
+ SELECT 1 FROM execution_runs retry_source
2165
+ WHERE retry_source.id = NEW.retry_of_check_repair_run_id
2166
+ AND retry_source.project_id = repair.project_id
2167
+ AND retry_source.kind = 'check_repair'
2168
+ AND retry_source.status IN ('completed', 'failed', 'cancelled', 'interrupted')
2169
+ ))
2170
+ AND ((NEW.automation_progression_run_id IS NULL
2171
+ AND repair.parent_run_id IS NULL AND repair.initiated_by = 'user'
2172
+ AND source.parent_run_id IS NULL AND source.initiated_by = 'user')
2173
+ OR (NEW.automation_progression_run_id = repair.parent_run_id AND repair.initiated_by = 'automation'
2174
+ AND source.parent_run_id = NEW.automation_progression_run_id AND source.initiated_by = 'automation'
2175
+ AND EXISTS (
2176
+ SELECT 1 FROM execution_runs progression
2177
+ WHERE progression.id = NEW.automation_progression_run_id
2178
+ AND progression.project_id = repair.project_id
2179
+ AND progression.kind = 'automation_progression'
2180
+ AND progression.status IN ('queued', 'running', 'waiting')
2181
+ )))
2182
+ )
2183
+ BEGIN
2184
+ SELECT RAISE(ABORT, 'Invalid check repair details');
2185
+ END;
2186
+
2187
+ CREATE TRIGGER IF NOT EXISTS validate_check_repair_diagnostic_provenance_insert
2188
+ BEFORE INSERT ON check_repair_diagnostic_provenance
2189
+ WHEN NOT EXISTS (
2190
+ SELECT 1
2191
+ FROM check_repair_details repair
2192
+ JOIN check_attempt_diagnostics diagnostic ON diagnostic.id = NEW.diagnostic_id
2193
+ JOIN check_attempt_details attempt ON attempt.execution_run_id = NEW.attempt_run_id
2194
+ JOIN execution_runs attempt_run ON attempt_run.id = attempt.execution_run_id
2195
+ JOIN check_attempt_diagnostic_parsers parser ON parser.attempt_run_id = attempt.execution_run_id
2196
+ WHERE repair.execution_run_id = NEW.check_repair_run_id
2197
+ AND diagnostic.attempt_run_id = attempt.execution_run_id
2198
+ AND diagnostic.definition_id = NEW.definition_id
2199
+ AND attempt.definition_id = NEW.definition_id
2200
+ AND attempt.batch_run_id = repair.source_batch_run_id
2201
+ AND attempt.outcome = 'command_failure' AND attempt_run.status = 'failed'
2202
+ AND attempt.output_retention_state = 'retained' AND length(attempt.retained_output) > 0
2203
+ AND parser.status = 'complete' AND parser.retention_state = 'retained'
2204
+ )
2205
+ BEGIN
2206
+ SELECT RAISE(ABORT, 'Invalid check repair diagnostic provenance');
2207
+ END;
2208
+
2209
+ CREATE TRIGGER IF NOT EXISTS validate_check_repair_raw_output_provenance_insert
2210
+ BEFORE INSERT ON check_repair_raw_output_provenance
2211
+ WHEN NOT EXISTS (
2212
+ SELECT 1
2213
+ FROM check_repair_details repair
2214
+ JOIN execution_runs repair_run ON repair_run.id = repair.execution_run_id
2215
+ JOIN check_attempt_details attempt ON attempt.execution_run_id = NEW.attempt_run_id
2216
+ JOIN execution_runs attempt_run ON attempt_run.id = attempt.execution_run_id
2217
+ AND attempt_run.project_id = repair_run.project_id
2218
+ JOIN execution_runs batch_run ON batch_run.id = attempt.batch_run_id
2219
+ AND batch_run.project_id = repair_run.project_id
2220
+ WHERE repair.execution_run_id = NEW.check_repair_run_id
2221
+ AND repair_run.kind = 'check_repair'
2222
+ AND attempt.definition_id = NEW.definition_id
2223
+ AND attempt.batch_run_id = repair.source_batch_run_id
2224
+ AND attempt.outcome = 'command_failure'
2225
+ AND attempt_run.kind = 'check_attempt' AND attempt_run.status = 'failed'
2226
+ AND batch_run.kind = 'check_batch' AND batch_run.status = 'failed'
2227
+ AND attempt.output_retention_state = 'retained'
2228
+ AND length(attempt.retained_output) > 0
2229
+ AND attempt.final_workspace_identity_json IS NOT NULL
2230
+ )
2231
+ BEGIN
2232
+ SELECT RAISE(ABORT, 'Invalid check repair raw output provenance');
2233
+ END;
2234
+
2235
+ CREATE TRIGGER IF NOT EXISTS validate_check_repair_follow_up_update
2236
+ BEFORE UPDATE OF follow_up_run_id ON check_repair_details
2237
+ WHEN NEW.follow_up_run_id IS NOT OLD.follow_up_run_id AND (
2238
+ OLD.follow_up_run_id IS NOT NULL OR NEW.follow_up_run_id IS NULL OR NOT EXISTS (
2239
+ SELECT 1
2240
+ FROM execution_runs repair
2241
+ JOIN execution_runs follow_up ON follow_up.id = NEW.follow_up_run_id
2242
+ AND follow_up.project_id = repair.project_id
2243
+ WHERE repair.id = OLD.execution_run_id AND repair.kind = 'check_repair'
2244
+ AND follow_up.kind = 'build_follow_up' AND follow_up.parent_run_id = repair.id
2245
+ )
2246
+ )
2247
+ BEGIN
2248
+ SELECT RAISE(ABORT, 'Invalid check repair follow-up ownership');
2249
+ END;
2250
+
2251
+ CREATE TRIGGER IF NOT EXISTS validate_check_repair_rerun_update
2252
+ BEFORE UPDATE OF rerun_batch_run_id ON check_repair_details
2253
+ WHEN NEW.rerun_batch_run_id IS NOT OLD.rerun_batch_run_id AND (
2254
+ OLD.rerun_batch_run_id IS NOT NULL OR NEW.rerun_batch_run_id IS NULL OR NOT EXISTS (
2255
+ SELECT 1
2256
+ FROM execution_runs repair
2257
+ JOIN execution_runs rerun ON rerun.id = NEW.rerun_batch_run_id
2258
+ AND rerun.project_id = repair.project_id
2259
+ JOIN check_batch_details rerun_details ON rerun_details.execution_run_id = rerun.id
2260
+ WHERE repair.id = OLD.execution_run_id AND repair.kind = 'check_repair'
2261
+ AND rerun.kind = 'check_batch'
2262
+ AND rerun_details.rerun_of_batch_run_id = OLD.source_batch_run_id
2263
+ AND rerun_details.target_kind = OLD.target_kind
2264
+ AND rerun_details.target_bundle_id IS OLD.target_bundle_id
2265
+ AND rerun_details.automation_boundary_purpose IS OLD.automation_boundary_purpose
2266
+ AND ((OLD.automation_progression_run_id IS NULL
2267
+ AND rerun.initiated_by = 'user' AND rerun.parent_run_id IS NULL)
2268
+ OR (OLD.automation_progression_run_id IS NOT NULL
2269
+ AND rerun.initiated_by = 'automation'
2270
+ AND rerun.parent_run_id = OLD.automation_progression_run_id))
2271
+ )
2272
+ )
2273
+ BEGIN
2274
+ SELECT RAISE(ABORT, 'Invalid check repair rerun ownership');
2275
+ END;
2276
+
2277
+ CREATE TRIGGER IF NOT EXISTS preserve_check_repair_terminal_result
2278
+ BEFORE UPDATE OF terminal_result ON check_repair_details
2279
+ WHEN OLD.terminal_result IS NOT NULL AND NEW.terminal_result IS NOT OLD.terminal_result
2280
+ BEGIN
2281
+ SELECT RAISE(ABORT, 'Check repair terminal result is immutable');
2282
+ END;
2283
+ `);
1872
2284
  db.exec(`
1873
2285
  CREATE TABLE IF NOT EXISTS check_gate_evaluations (
1874
2286
  id TEXT PRIMARY KEY,
@@ -2075,6 +2487,7 @@ db.prepare(`
2075
2487
  `).run();
2076
2488
  db.exec('DROP TRIGGER IF EXISTS validate_check_batch_details_insert');
2077
2489
  db.exec('DROP TRIGGER IF EXISTS preserve_check_batch_snapshots');
2490
+ db.exec('DROP TRIGGER IF EXISTS preserve_completed_check_batch_details');
2078
2491
  db.exec(`
2079
2492
  CREATE TRIGGER IF NOT EXISTS preserve_check_batch_snapshots
2080
2493
  BEFORE UPDATE OF execution_run_id, target_kind, target_bundle_id, target_label,
@@ -2084,6 +2497,13 @@ db.exec(`
2084
2497
  SELECT RAISE(ABORT, 'Check batch snapshots are immutable');
2085
2498
  END;
2086
2499
 
2500
+ CREATE TRIGGER IF NOT EXISTS preserve_completed_check_batch_details
2501
+ BEFORE UPDATE OF final_workspace_identity_json ON check_batch_details
2502
+ WHEN OLD.final_workspace_identity_json IS NOT NULL
2503
+ BEGIN
2504
+ SELECT RAISE(ABORT, 'Completed check batch details are immutable');
2505
+ END;
2506
+
2087
2507
  CREATE TRIGGER IF NOT EXISTS preserve_check_attempt_snapshots
2088
2508
  BEFORE UPDATE OF execution_run_id, batch_run_id, definition_id, command_snapshot_json,
2089
2509
  definition_fingerprint, initial_workspace_identity_json, rerun_of_attempt_run_id
@@ -2137,14 +2557,28 @@ db.exec(`
2137
2557
  OR (NEW.target_kind = 'repo_root' AND NEW.target_bundle_id IS NULL
2138
2558
  AND bundle.kind = 'project_root')
2139
2559
  )
2140
- AND NOT EXISTS (
2141
- SELECT 1 FROM execution_runs sibling
2560
+ AND NOT EXISTS (
2561
+ SELECT 1 FROM execution_runs sibling
2142
2562
  WHERE sibling.project_id = run.project_id
2143
2563
  AND sibling.parent_run_id = progression.id
2144
2564
  AND sibling.id <> run.id
2145
- AND sibling.kind IN ('check_batch', 'review', 'automation_review_fix', 'automation_commit', 'automation_push', 'automation_pull_request')
2146
- AND sibling.status IN ('queued', 'running', 'waiting')
2147
- )
2565
+ AND sibling.kind IN ('check_batch', 'check_repair', 'review', 'automation_review_fix', 'automation_commit', 'automation_push', 'automation_pull_request')
2566
+ AND sibling.status IN ('queued', 'running', 'waiting')
2567
+ AND NOT (
2568
+ sibling.kind = 'check_repair'
2569
+ AND NEW.rerun_of_batch_run_id IS NOT NULL
2570
+ AND EXISTS (
2571
+ SELECT 1 FROM check_repair_details repair_details
2572
+ WHERE repair_details.execution_run_id = sibling.id
2573
+ AND repair_details.source_batch_run_id = NEW.rerun_of_batch_run_id
2574
+ AND repair_details.terminal_result IS NULL
2575
+ AND repair_details.automation_progression_run_id = progression.id
2576
+ AND repair_details.automation_boundary_purpose = NEW.automation_boundary_purpose
2577
+ AND repair_details.target_kind = NEW.target_kind
2578
+ AND repair_details.target_bundle_id IS NEW.target_bundle_id
2579
+ )
2580
+ )
2581
+ )
2148
2582
  )
2149
2583
  )
2150
2584
  AND (run.initiated_by = 'automation' OR NEW.automation_boundary_purpose IS NULL)
@@ -2414,6 +2848,12 @@ db.exec('CREATE INDEX IF NOT EXISTS idx_github_actions_details_dispatch ON githu
2414
2848
  db.exec('CREATE INDEX IF NOT EXISTS idx_check_batches_rerun ON check_batch_details(rerun_of_batch_run_id)');
2415
2849
  db.exec('CREATE INDEX IF NOT EXISTS idx_check_attempts_batch ON check_attempt_details(batch_run_id, definition_id)');
2416
2850
  db.exec('CREATE INDEX IF NOT EXISTS idx_check_attempts_rerun ON check_attempt_details(rerun_of_attempt_run_id)');
2851
+ db.exec('CREATE INDEX IF NOT EXISTS idx_check_diagnostics_attempt ON check_attempt_diagnostics(attempt_run_id, ordinal)');
2852
+ db.exec('CREATE INDEX IF NOT EXISTS idx_check_diagnostic_parsers_retention ON check_attempt_diagnostic_parsers(retention_state, attempt_run_id)');
2853
+ db.exec('CREATE INDEX IF NOT EXISTS idx_check_repairs_source ON check_repair_details(source_batch_run_id, created_at DESC)');
2854
+ db.exec('CREATE INDEX IF NOT EXISTS idx_check_repairs_progression ON check_repair_details(automation_progression_run_id, terminal_result)');
2855
+ db.exec('CREATE INDEX IF NOT EXISTS idx_check_repair_diagnostics_attempt ON check_repair_diagnostic_provenance(attempt_run_id)');
2856
+ db.exec('CREATE INDEX IF NOT EXISTS idx_check_repair_raw_output_attempt ON check_repair_raw_output_provenance(attempt_run_id)');
2417
2857
  db.exec('CREATE INDEX IF NOT EXISTS idx_check_gate_evaluations_target ON check_gate_evaluations(project_id, target_kind, target_bundle_id, created_at DESC, id DESC)');
2418
2858
  db.exec('CREATE INDEX IF NOT EXISTS idx_check_gate_evaluations_batch ON check_gate_evaluations(source_batch_run_id)');
2419
2859
  db.exec('CREATE INDEX IF NOT EXISTS idx_check_gate_evaluation_attempts_run ON check_gate_evaluation_attempts(attempt_run_id)');
@@ -2537,6 +2977,7 @@ db.exec(`
2537
2977
  fix_loop_active INTEGER NOT NULL DEFAULT 0,
2538
2978
  automation_progression_run_id TEXT,
2539
2979
  automation_paused_stage_run_id TEXT,
2980
+ automation_paused_boundary_purpose TEXT,
2540
2981
  automation_pause_reason_code TEXT,
2541
2982
  automation_paused_code TEXT,
2542
2983
  automation_paused_reason TEXT,
@@ -2545,12 +2986,16 @@ db.exec(`
2545
2986
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
2546
2987
  PRIMARY KEY (project_id, worktree_bundle_id),
2547
2988
  FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
2548
- FOREIGN KEY (worktree_bundle_id) REFERENCES worktree_bundles(id) ON DELETE CASCADE
2989
+ FOREIGN KEY (worktree_bundle_id) REFERENCES worktree_bundles(id) ON DELETE CASCADE,
2990
+ CHECK (automation_paused_boundary_purpose IS NULL OR automation_paused_boundary_purpose IN (
2991
+ 'automation_review', 'automation_commit', 'automation_push', 'automation_pull_request'
2992
+ ))
2549
2993
  )
2550
2994
  `);
2551
2995
  ensureColumn('bundle_automation_state', 'automation_paused_code', 'TEXT');
2552
2996
  ensureColumn('bundle_automation_state', 'automation_progression_run_id', 'TEXT');
2553
2997
  ensureColumn('bundle_automation_state', 'automation_paused_stage_run_id', 'TEXT');
2998
+ ensureColumn('bundle_automation_state', 'automation_paused_boundary_purpose', 'TEXT');
2554
2999
  ensureColumn('bundle_automation_state', 'automation_pause_reason_code', 'TEXT');
2555
3000
  db.exec(`
2556
3001
  CREATE TABLE IF NOT EXISTS automation_stage_details (