@straiffi/archon 1.7.9 → 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 (170) hide show
  1. package/dist/client/assets/{ActivityView-CDLQOXZm.js → ActivityView-EVy76nes.js} +1 -1
  2. package/dist/client/assets/{GitHubActionsDialog-DYxLX2HS.js → GitHubActionsDialog-D53aA0Fv.js} +1 -1
  3. package/dist/client/assets/VerificationDialog-Dm5DcY8F.js +4 -0
  4. package/dist/client/assets/{architectureDiagram-3BPJPVTR-ByNXcCIO.js → architectureDiagram-3BPJPVTR-CmMRkze6.js} +1 -1
  5. package/dist/client/assets/{blockDiagram-GPEHLZMM-ByykLAaG.js → blockDiagram-GPEHLZMM-BgLsRgxM.js} +1 -1
  6. package/dist/client/assets/{c4Diagram-AAUBKEIU-CmWA4Pli.js → c4Diagram-AAUBKEIU-C3WJl13c.js} +1 -1
  7. package/dist/client/assets/channel-xqaERdN6.js +1 -0
  8. package/dist/client/assets/{chunk-2J33WTMH-CTgbXRh4.js → chunk-2J33WTMH-BfH4_PkQ.js} +1 -1
  9. package/dist/client/assets/{chunk-3OPIFGDE-D3FajVfq.js → chunk-3OPIFGDE-CkVGPLM4.js} +1 -1
  10. package/dist/client/assets/{chunk-5ZQYHXKU-CUMg_Vfo.js → chunk-5ZQYHXKU-CDTwT753.js} +1 -1
  11. package/dist/client/assets/{chunk-727SXJPM-Oc9MgxZD.js → chunk-727SXJPM-CKEhBrr_.js} +1 -1
  12. package/dist/client/assets/{chunk-AQP2D5EJ-5JZboHeP.js → chunk-AQP2D5EJ-D5QPK_k7.js} +1 -1
  13. package/dist/client/assets/{chunk-CSCIHK7Q-BpkSMHjB.js → chunk-CSCIHK7Q-BU4Ysr_2.js} +1 -1
  14. package/dist/client/assets/{chunk-KSCS5N6A-BPBMAswO.js → chunk-KSCS5N6A-B9lHLGg1.js} +1 -1
  15. package/dist/client/assets/{chunk-L5ZTLDWV-BA2sHmu7.js → chunk-L5ZTLDWV-BrNsmxtD.js} +1 -1
  16. package/dist/client/assets/{chunk-LZXEDZCA-Blc9q-fQ.js → chunk-LZXEDZCA-CVgZc1nv.js} +2 -2
  17. package/dist/client/assets/{chunk-ND2GUHAM-GlVS74JP.js → chunk-ND2GUHAM-DWWdi42a.js} +1 -1
  18. package/dist/client/assets/{chunk-NZK2D7GU-fctBFnAm.js → chunk-NZK2D7GU-46-aRMvO.js} +1 -1
  19. package/dist/client/assets/{chunk-O5CBEL6O-eGs4DDLJ.js → chunk-O5CBEL6O-BW6wHmzD.js} +1 -1
  20. package/dist/client/assets/{chunk-WU5MYG2G-vxa50E7g.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-DXGXNVUp.js → dagre-BM42HDAG-CZ_BDahz.js} +1 -1
  24. package/dist/client/assets/{diagram-2AECGRRQ-BRYr1GvB.js → diagram-2AECGRRQ-CQKXQvjO.js} +1 -1
  25. package/dist/client/assets/{diagram-5GNKFQAL-BcwgMag4.js → diagram-5GNKFQAL-Dgsh82oA.js} +1 -1
  26. package/dist/client/assets/{diagram-KO2AKTUF-Delk7lbr.js → diagram-KO2AKTUF-DUwmm3sV.js} +1 -1
  27. package/dist/client/assets/{diagram-LMA3HP47-BVtc_fjo.js → diagram-LMA3HP47-DLGz0g10.js} +1 -1
  28. package/dist/client/assets/{diagram-OG6HWLK6-weIPvUz5.js → diagram-OG6HWLK6-CjS6v8Zz.js} +1 -1
  29. package/dist/client/assets/{erDiagram-TEJ5UH35-DKde70dA.js → erDiagram-TEJ5UH35-DHaCFHn9.js} +1 -1
  30. package/dist/client/assets/{flowDiagram-I6XJVG4X-B7Jrk-6c.js → flowDiagram-I6XJVG4X-E4LSVqs6.js} +1 -1
  31. package/dist/client/assets/{ganttDiagram-6RSMTGT7-CDzWDgnA.js → ganttDiagram-6RSMTGT7-BWywa_xn.js} +1 -1
  32. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-DYZCryuN.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-DmQOgVKK.js → infoDiagram-5YYISTIA-BX7HzDWX.js} +1 -1
  36. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-DCpu-q-Z.js → ishikawaDiagram-YF4QCWOH-CEnWCNes.js} +1 -1
  37. package/dist/client/assets/{journeyDiagram-JHISSGLW-DhBoglhI.js → journeyDiagram-JHISSGLW-MQPDgPxD.js} +1 -1
  38. package/dist/client/assets/{kanban-definition-UN3LZRKU-BSjvGFTY.js → kanban-definition-UN3LZRKU-PwVLKAnN.js} +1 -1
  39. package/dist/client/assets/{line-ClKBZwDr.js → line-BJMnG1sl.js} +1 -1
  40. package/dist/client/assets/{mermaid-parser.core-BRA4mJ40.js → mermaid-parser.core-Bwv8qN83.js} +1 -1
  41. package/dist/client/assets/{mermaid.core-BZ7kSfEt.js → mermaid.core-DpFOXZmb.js} +3 -3
  42. package/dist/client/assets/{mindmap-definition-RKZ34NQL-DoUdLHgj.js → mindmap-definition-RKZ34NQL-Dt-9JT_z.js} +1 -1
  43. package/dist/client/assets/{pieDiagram-4H26LBE5-NVnzqltb.js → pieDiagram-4H26LBE5-aD3cg6m3.js} +1 -1
  44. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-DOITgkan.js → quadrantDiagram-W4KKPZXB-DUh4hgmW.js} +1 -1
  45. package/dist/client/assets/{requirementDiagram-4Y6WPE33-D0VPxrFE.js → requirementDiagram-4Y6WPE33-DOgz-iLT.js} +1 -1
  46. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-Bx0uU7xV.js → sankeyDiagram-5OEKKPKP-BqpDXW6-.js} +1 -1
  47. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-B4lFL6cO.js → sequenceDiagram-3UESZ5HK-BM0Gvqia.js} +1 -1
  48. package/dist/client/assets/{stateDiagram-AJRCARHV-CsLVsMZ4.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-BkcYpPFI.js → timeline-definition-PNZ67QCA-gqiDwxVu.js} +1 -1
  51. package/dist/client/assets/{vennDiagram-CIIHVFJN-Xc5f2sRQ.js → vennDiagram-CIIHVFJN-MxeqqqyG.js} +1 -1
  52. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-n3Dpk02Q.js → wardleyDiagram-YWT4CUSO-pMgGO6cB.js} +1 -1
  53. package/dist/client/assets/{xychartDiagram-2RQKCTM6-BTMzF8zg.js → xychartDiagram-2RQKCTM6-_VK_NZDn.js} +1 -1
  54. package/dist/client/index.html +2 -2
  55. package/dist/server/db.js +467 -11
  56. package/dist/server/db.js.map +1 -1
  57. package/dist/server/index.js +356 -150
  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/agent.js +5 -4
  62. package/dist/server/lib/agent.js.map +1 -1
  63. package/dist/server/lib/automationCheckGate.js +211 -59
  64. package/dist/server/lib/automationCheckGate.js.map +1 -1
  65. package/dist/server/lib/automationProgression.js +78 -10
  66. package/dist/server/lib/automationProgression.js.map +1 -1
  67. package/dist/server/lib/automationReconciliation.js +65 -0
  68. package/dist/server/lib/automationReconciliation.js.map +1 -1
  69. package/dist/server/lib/automationResumeDecision.js +82 -20
  70. package/dist/server/lib/automationResumeDecision.js.map +1 -1
  71. package/dist/server/lib/automationReviewGate.js +147 -0
  72. package/dist/server/lib/automationReviewGate.js.map +1 -0
  73. package/dist/server/lib/bundleActivity.js +20 -0
  74. package/dist/server/lib/bundleActivity.js.map +1 -1
  75. package/dist/server/lib/bundleReviewOperations.js +36 -5
  76. package/dist/server/lib/bundleReviewOperations.js.map +1 -1
  77. package/dist/server/lib/chatTicketProposals.js +2 -1
  78. package/dist/server/lib/chatTicketProposals.js.map +1 -1
  79. package/dist/server/lib/checkDefinitions.js +11 -0
  80. package/dist/server/lib/checkDefinitions.js.map +1 -1
  81. package/dist/server/lib/checkDiagnosticParsers.js +301 -0
  82. package/dist/server/lib/checkDiagnosticParsers.js.map +1 -0
  83. package/dist/server/lib/checkDiagnostics.js +142 -0
  84. package/dist/server/lib/checkDiagnostics.js.map +1 -0
  85. package/dist/server/lib/checkGateEvaluations.js +92 -4
  86. package/dist/server/lib/checkGateEvaluations.js.map +1 -1
  87. package/dist/server/lib/checkRepair.js +1031 -0
  88. package/dist/server/lib/checkRepair.js.map +1 -0
  89. package/dist/server/lib/checkRepairLifecycle.js +56 -0
  90. package/dist/server/lib/checkRepairLifecycle.js.map +1 -0
  91. package/dist/server/lib/checkRepairReconciliation.js +145 -0
  92. package/dist/server/lib/checkRepairReconciliation.js.map +1 -0
  93. package/dist/server/lib/checkRunner.js +142 -25
  94. package/dist/server/lib/checkRunner.js.map +1 -1
  95. package/dist/server/lib/checkRuns.js +75 -9
  96. package/dist/server/lib/checkRuns.js.map +1 -1
  97. package/dist/server/lib/executionReconciliation.js +21 -11
  98. package/dist/server/lib/executionReconciliation.js.map +1 -1
  99. package/dist/server/lib/executionRetryPredicates.js +3 -1
  100. package/dist/server/lib/executionRetryPredicates.js.map +1 -1
  101. package/dist/server/lib/executionRunRetention.js +24 -3
  102. package/dist/server/lib/executionRunRetention.js.map +1 -1
  103. package/dist/server/lib/executionRuns.js +5 -2
  104. package/dist/server/lib/executionRuns.js.map +1 -1
  105. package/dist/server/lib/git.js +5 -1
  106. package/dist/server/lib/git.js.map +1 -1
  107. package/dist/server/lib/lightweightPrompt.js +2 -1
  108. package/dist/server/lib/lightweightPrompt.js.map +1 -1
  109. package/dist/server/lib/planModeQuestions.js +2 -0
  110. package/dist/server/lib/planModeQuestions.js.map +1 -1
  111. package/dist/server/lib/planQuestions.js +39 -7
  112. package/dist/server/lib/planQuestions.js.map +1 -1
  113. package/dist/server/lib/projectAutoConfig.js +2 -1
  114. package/dist/server/lib/projectAutoConfig.js.map +1 -1
  115. package/dist/server/lib/projectMemorySuggestions.js +2 -1
  116. package/dist/server/lib/projectMemorySuggestions.js.map +1 -1
  117. package/dist/server/lib/projects.js +57 -9
  118. package/dist/server/lib/projects.js.map +1 -1
  119. package/dist/server/lib/pullRequestContent.js +14 -0
  120. package/dist/server/lib/pullRequestContent.js.map +1 -1
  121. package/dist/server/lib/requiredCheckPolicy.js +88 -18
  122. package/dist/server/lib/requiredCheckPolicy.js.map +1 -1
  123. package/dist/server/lib/requiredCheckPolicyPrompt.js +46 -0
  124. package/dist/server/lib/requiredCheckPolicyPrompt.js.map +1 -0
  125. package/dist/server/lib/run.js +3 -2
  126. package/dist/server/lib/run.js.map +1 -1
  127. package/dist/server/lib/specDraft.js +6 -0
  128. package/dist/server/lib/specDraft.js.map +1 -1
  129. package/dist/server/lib/specResources.js +42 -0
  130. package/dist/server/lib/specResources.js.map +1 -0
  131. package/dist/server/lib/specs.js +9 -5
  132. package/dist/server/lib/specs.js.map +1 -1
  133. package/dist/server/lib/terminal.js +5 -7
  134. package/dist/server/lib/terminal.js.map +1 -1
  135. package/dist/server/lib/testSessions.js +2 -2
  136. package/dist/server/lib/testSessions.js.map +1 -1
  137. package/dist/server/lib/ticketAutomation.js +10 -3
  138. package/dist/server/lib/ticketAutomation.js.map +1 -1
  139. package/dist/server/lib/ticketAutomationCommit.js +37 -11
  140. package/dist/server/lib/ticketAutomationCommit.js.map +1 -1
  141. package/dist/server/lib/ticketFollowUpOperations.js +24 -9
  142. package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
  143. package/dist/server/lib/tickets.js +18 -0
  144. package/dist/server/lib/tickets.js.map +1 -1
  145. package/dist/server/lib/types.js +1 -0
  146. package/dist/server/lib/types.js.map +1 -1
  147. package/dist/server/lib/workspaceProcessEnvironment.js +21 -0
  148. package/dist/server/lib/workspaceProcessEnvironment.js.map +1 -0
  149. package/dist/server/workers/build.js +41 -28
  150. package/dist/server/workers/build.js.map +1 -1
  151. package/dist/server/workers/chat.js +4 -3
  152. package/dist/server/workers/chat.js.map +1 -1
  153. package/dist/server/workers/followUp.js +99 -103
  154. package/dist/server/workers/followUp.js.map +1 -1
  155. package/dist/server/workers/plan.js +9 -4
  156. package/dist/server/workers/plan.js.map +1 -1
  157. package/dist/server/workers/planFollowUp.js +5 -6
  158. package/dist/server/workers/planFollowUp.js.map +1 -1
  159. package/dist/server/workers/review.js +38 -6
  160. package/dist/server/workers/review.js.map +1 -1
  161. package/dist/server/workers/specSession.js +10 -4
  162. package/dist/server/workers/specSession.js.map +1 -1
  163. package/package.json +1 -1
  164. package/dist/client/assets/VerificationDialog-DEKvZG75.js +0 -4
  165. package/dist/client/assets/channel-BvcRv90i.js +0 -1
  166. package/dist/client/assets/classDiagram-4FO5ZUOK-IuovJyxl.js +0 -1
  167. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BBJ3avX6.js +0 -1
  168. package/dist/client/assets/index-BlKOx9Vf.css +0 -2
  169. package/dist/client/assets/index-CmaBDvIB.js +0 -273
  170. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-CvrvaIdF.js +0 -1
package/dist/server/db.js CHANGED
@@ -58,6 +58,7 @@ db.exec(`
58
58
  run_services TEXT,
59
59
  check_definitions TEXT,
60
60
  required_check_definition_ids TEXT NOT NULL DEFAULT '[]',
61
+ pre_review_check_definition_ids TEXT NOT NULL DEFAULT '[]',
61
62
  test_commands TEXT,
62
63
  run_ide TEXT,
63
64
  preview_service_name TEXT,
@@ -130,11 +131,14 @@ ensureColumn('worktree_bundles', 'kind', "TEXT NOT NULL DEFAULT 'worktree'");
130
131
  ensureColumn('worktree_bundles', 'automation_depth', 'TEXT');
131
132
  ensureColumn('worktree_bundles', 'automation_review_fix_enabled', 'INTEGER');
132
133
  ensureColumn('worktree_bundles', 'automation_pause_on_open_questions', 'INTEGER');
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');
133
136
  ensureColumn('projects', 'worktree_sync', 'TEXT');
134
137
  ensureColumn('projects', 'active_target_kind', "TEXT NOT NULL DEFAULT 'repo_root'");
135
138
  ensureColumn('projects', 'active_target_bundle_id', 'TEXT');
136
139
  ensureColumn('projects', 'check_definitions', 'TEXT');
137
140
  ensureColumn('projects', 'required_check_definition_ids', "TEXT NOT NULL DEFAULT '[]'");
141
+ ensureColumn('projects', 'pre_review_check_definition_ids', "TEXT NOT NULL DEFAULT '[]'");
138
142
  ensureColumn('projects', 'test_commands', 'TEXT');
139
143
  ensureColumn('projects', 'helper_model', 'TEXT');
140
144
  ensureColumn('projects', 'helper_variant', 'TEXT');
@@ -821,6 +825,7 @@ db.exec(`
821
825
  likely_files_json TEXT,
822
826
  tickets_json TEXT,
823
827
  dependencies_json TEXT,
828
+ resource_urls_json TEXT,
824
829
  mermaid TEXT,
825
830
  mockup TEXT,
826
831
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
@@ -830,6 +835,7 @@ db.exec(`
830
835
  ensureColumn('spec_snapshots', 'plan_text', 'TEXT');
831
836
  ensureColumn('spec_snapshots', 'mockup', 'TEXT');
832
837
  ensureColumn('spec_snapshots', 'file_relation_graph', 'TEXT');
838
+ ensureColumn('spec_snapshots', 'resource_urls_json', 'TEXT');
833
839
  db.exec(`
834
840
  CREATE TABLE IF NOT EXISTS spec_message_attachments (
835
841
  attachment_id TEXT PRIMARY KEY,
@@ -1809,6 +1815,7 @@ db.exec(`
1809
1815
  target_label TEXT,
1810
1816
  selected_definition_snapshots_json TEXT NOT NULL,
1811
1817
  initial_workspace_identity_json TEXT NOT NULL,
1818
+ final_workspace_identity_json TEXT,
1812
1819
  configuration_fingerprint TEXT NOT NULL,
1813
1820
  stop_requested INTEGER NOT NULL DEFAULT 0,
1814
1821
  queued_count INTEGER NOT NULL DEFAULT 0,
@@ -1818,6 +1825,7 @@ db.exec(`
1818
1825
  cancelled_count INTEGER NOT NULL DEFAULT 0,
1819
1826
  interrupted_count INTEGER NOT NULL DEFAULT 0,
1820
1827
  rerun_of_batch_run_id TEXT,
1828
+ automation_boundary_purpose TEXT,
1821
1829
  FOREIGN KEY (execution_run_id) REFERENCES execution_runs(id) ON DELETE CASCADE,
1822
1830
  FOREIGN KEY (rerun_of_batch_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
1823
1831
  CHECK (target_kind IN ('repo_root', 'bundle')),
@@ -1826,9 +1834,14 @@ db.exec(`
1826
1834
  CHECK (length(configuration_fingerprint) = 64 AND configuration_fingerprint NOT GLOB '*[^0-9a-f]*'),
1827
1835
  CHECK (stop_requested IN (0, 1)),
1828
1836
  CHECK (queued_count >= 0 AND running_count >= 0 AND passed_count >= 0 AND failed_count >= 0
1829
- AND cancelled_count >= 0 AND interrupted_count >= 0)
1837
+ AND cancelled_count >= 0 AND interrupted_count >= 0),
1838
+ CHECK (automation_boundary_purpose IS NULL OR automation_boundary_purpose IN (
1839
+ 'automation_review', 'automation_commit', 'automation_push', 'automation_pull_request'
1840
+ ))
1830
1841
  )
1831
1842
  `);
1843
+ ensureColumn('check_batch_details', 'automation_boundary_purpose', 'TEXT');
1844
+ ensureColumn('check_batch_details', 'final_workspace_identity_json', 'TEXT');
1832
1845
  db.exec(`
1833
1846
  CREATE TABLE IF NOT EXISTS check_attempt_details (
1834
1847
  execution_run_id TEXT PRIMARY KEY,
@@ -1854,13 +1867,420 @@ db.exec(`
1854
1867
  FOREIGN KEY (rerun_of_attempt_run_id) REFERENCES execution_runs(id) ON DELETE RESTRICT,
1855
1868
  CHECK (length(definition_id) BETWEEN 1 AND 500),
1856
1869
  CHECK (length(definition_fingerprint) = 64 AND definition_fingerprint NOT GLOB '*[^0-9a-f]*'),
1857
- 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',
1858
1872
  'workspace_changed_before_start', 'user_stop', 'restart_loss', 'shutdown_loss')),
1859
1873
  CHECK (output_revision >= 0 AND retained_start_offset >= 0 AND retained_end_offset >= retained_start_offset
1860
1874
  AND total_persisted_bytes >= retained_end_offset),
1861
1875
  CHECK (output_retention_state IN ('retained', 'expired'))
1862
1876
  )
1863
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
+ `);
1864
2284
  db.exec(`
1865
2285
  CREATE TABLE IF NOT EXISTS check_gate_evaluations (
1866
2286
  id TEXT PRIMARY KEY,
@@ -2066,15 +2486,24 @@ db.prepare(`
2066
2486
  WHERE retained_end_offset = 0 AND total_persisted_bytes > 0
2067
2487
  `).run();
2068
2488
  db.exec('DROP TRIGGER IF EXISTS validate_check_batch_details_insert');
2489
+ db.exec('DROP TRIGGER IF EXISTS preserve_check_batch_snapshots');
2490
+ db.exec('DROP TRIGGER IF EXISTS preserve_completed_check_batch_details');
2069
2491
  db.exec(`
2070
2492
  CREATE TRIGGER IF NOT EXISTS preserve_check_batch_snapshots
2071
2493
  BEFORE UPDATE OF execution_run_id, target_kind, target_bundle_id, target_label,
2072
2494
  selected_definition_snapshots_json, initial_workspace_identity_json, configuration_fingerprint,
2073
- rerun_of_batch_run_id ON check_batch_details
2495
+ rerun_of_batch_run_id, automation_boundary_purpose ON check_batch_details
2074
2496
  BEGIN
2075
2497
  SELECT RAISE(ABORT, 'Check batch snapshots are immutable');
2076
2498
  END;
2077
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
+
2078
2507
  CREATE TRIGGER IF NOT EXISTS preserve_check_attempt_snapshots
2079
2508
  BEFORE UPDATE OF execution_run_id, batch_run_id, definition_id, command_snapshot_json,
2080
2509
  definition_fingerprint, initial_workspace_identity_json, rerun_of_attempt_run_id
@@ -2101,7 +2530,8 @@ db.exec(`
2101
2530
  AND (
2102
2531
  (run.parent_run_id IS NULL AND run.initiated_by <> 'automation')
2103
2532
  OR (
2104
- run.initiated_by = 'automation'
2533
+ run.initiated_by = 'automation'
2534
+ AND NEW.automation_boundary_purpose IN ('automation_review', 'automation_commit', 'automation_push', 'automation_pull_request')
2105
2535
  AND EXISTS (
2106
2536
  SELECT 1
2107
2537
  FROM execution_runs progression
@@ -2127,17 +2557,32 @@ db.exec(`
2127
2557
  OR (NEW.target_kind = 'repo_root' AND NEW.target_bundle_id IS NULL
2128
2558
  AND bundle.kind = 'project_root')
2129
2559
  )
2130
- AND NOT EXISTS (
2131
- SELECT 1 FROM execution_runs sibling
2560
+ AND NOT EXISTS (
2561
+ SELECT 1 FROM execution_runs sibling
2132
2562
  WHERE sibling.project_id = run.project_id
2133
2563
  AND sibling.parent_run_id = progression.id
2134
2564
  AND sibling.id <> run.id
2135
- AND sibling.kind IN ('check_batch', 'review', 'automation_review_fix', 'automation_commit', 'automation_push', 'automation_pull_request')
2136
- AND sibling.status IN ('queued', 'running', 'waiting')
2137
- )
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
+ )
2138
2582
  )
2139
- )
2140
2583
  )
2584
+ AND (run.initiated_by = 'automation' OR NEW.automation_boundary_purpose IS NULL)
2585
+ )
2141
2586
  ) OR (
2142
2587
  NEW.rerun_of_batch_run_id IS NOT NULL AND NOT EXISTS (
2143
2588
  SELECT 1 FROM execution_runs source, execution_runs current
@@ -2403,6 +2848,12 @@ db.exec('CREATE INDEX IF NOT EXISTS idx_github_actions_details_dispatch ON githu
2403
2848
  db.exec('CREATE INDEX IF NOT EXISTS idx_check_batches_rerun ON check_batch_details(rerun_of_batch_run_id)');
2404
2849
  db.exec('CREATE INDEX IF NOT EXISTS idx_check_attempts_batch ON check_attempt_details(batch_run_id, definition_id)');
2405
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)');
2406
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)');
2407
2858
  db.exec('CREATE INDEX IF NOT EXISTS idx_check_gate_evaluations_batch ON check_gate_evaluations(source_batch_run_id)');
2408
2859
  db.exec('CREATE INDEX IF NOT EXISTS idx_check_gate_evaluation_attempts_run ON check_gate_evaluation_attempts(attempt_run_id)');
@@ -2526,6 +2977,7 @@ db.exec(`
2526
2977
  fix_loop_active INTEGER NOT NULL DEFAULT 0,
2527
2978
  automation_progression_run_id TEXT,
2528
2979
  automation_paused_stage_run_id TEXT,
2980
+ automation_paused_boundary_purpose TEXT,
2529
2981
  automation_pause_reason_code TEXT,
2530
2982
  automation_paused_code TEXT,
2531
2983
  automation_paused_reason TEXT,
@@ -2534,12 +2986,16 @@ db.exec(`
2534
2986
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
2535
2987
  PRIMARY KEY (project_id, worktree_bundle_id),
2536
2988
  FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
2537
- 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
+ ))
2538
2993
  )
2539
2994
  `);
2540
2995
  ensureColumn('bundle_automation_state', 'automation_paused_code', 'TEXT');
2541
2996
  ensureColumn('bundle_automation_state', 'automation_progression_run_id', 'TEXT');
2542
2997
  ensureColumn('bundle_automation_state', 'automation_paused_stage_run_id', 'TEXT');
2998
+ ensureColumn('bundle_automation_state', 'automation_paused_boundary_purpose', 'TEXT');
2543
2999
  ensureColumn('bundle_automation_state', 'automation_pause_reason_code', 'TEXT');
2544
3000
  db.exec(`
2545
3001
  CREATE TABLE IF NOT EXISTS automation_stage_details (