@straiffi/archon 1.10.9 → 1.10.12

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 (165) hide show
  1. package/dist/client/assets/ActivityView-BFn_Nhj4.js +1 -0
  2. package/dist/client/assets/GitHubActionsDialog-iZD86Yju.js +1 -0
  3. package/dist/client/assets/VerificationDialog-CqKE8t1d.js +4 -0
  4. package/dist/client/assets/{architectureDiagram-3BPJPVTR-BAIGV9Mj.js → architectureDiagram-3BPJPVTR-C8KefY67.js} +1 -1
  5. package/dist/client/assets/{blockDiagram-GPEHLZMM-B-5v5jSZ.js → blockDiagram-GPEHLZMM-BO2Q_Osr.js} +1 -1
  6. package/dist/client/assets/{c4Diagram-AAUBKEIU-C6wU415o.js → c4Diagram-AAUBKEIU-DGPkhbrK.js} +1 -1
  7. package/dist/client/assets/channel-DXKn3TOv.js +1 -0
  8. package/dist/client/assets/{chunk-2J33WTMH-COmvX2tP.js → chunk-2J33WTMH-Dtb7Xu8C.js} +1 -1
  9. package/dist/client/assets/{chunk-3OPIFGDE-BlANptdY.js → chunk-3OPIFGDE-Bnf4GbOF.js} +1 -1
  10. package/dist/client/assets/{chunk-5ZQYHXKU-ETyA2_GU.js → chunk-5ZQYHXKU-BWGid3g7.js} +1 -1
  11. package/dist/client/assets/{chunk-727SXJPM-D5-DudwF.js → chunk-727SXJPM-ScA8IRGP.js} +1 -1
  12. package/dist/client/assets/{chunk-AQP2D5EJ-k1AJ4sA3.js → chunk-AQP2D5EJ-Bygg04Ip.js} +1 -1
  13. package/dist/client/assets/{chunk-CSCIHK7Q-jfksXwY9.js → chunk-CSCIHK7Q-CxdDDtfN.js} +1 -1
  14. package/dist/client/assets/{chunk-KSCS5N6A-CHj0FDj9.js → chunk-KSCS5N6A-BgpZFsB5.js} +1 -1
  15. package/dist/client/assets/{chunk-L5ZTLDWV-1ODGxXhG.js → chunk-L5ZTLDWV-CKSew0OL.js} +1 -1
  16. package/dist/client/assets/{chunk-LZXEDZCA-Bgh9X2W0.js → chunk-LZXEDZCA-DVG9Rx0K.js} +2 -2
  17. package/dist/client/assets/{chunk-ND2GUHAM-DDkb3sp4.js → chunk-ND2GUHAM-CHBqNmuF.js} +1 -1
  18. package/dist/client/assets/{chunk-NZK2D7GU-B6B8PZ_-.js → chunk-NZK2D7GU-DvZYWn7V.js} +1 -1
  19. package/dist/client/assets/{chunk-O5CBEL6O-DhiUIFgj.js → chunk-O5CBEL6O-BL7lRTSe.js} +1 -1
  20. package/dist/client/assets/{chunk-WU5MYG2G-Dzd0fbP3.js → chunk-WU5MYG2G-C-il2wHZ.js} +1 -1
  21. package/dist/client/assets/classDiagram-4FO5ZUOK-U0fU20hT.js +1 -0
  22. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-C6bQNSxL.js +1 -0
  23. package/dist/client/assets/{dagre-BM42HDAG-DoNDMCXI.js → dagre-BM42HDAG-B00l5tLi.js} +1 -1
  24. package/dist/client/assets/{diagram-2AECGRRQ-ETDXSa5q.js → diagram-2AECGRRQ-Tum6g1_5.js} +1 -1
  25. package/dist/client/assets/{diagram-5GNKFQAL-CgTUep7e.js → diagram-5GNKFQAL-BK1GX5jc.js} +1 -1
  26. package/dist/client/assets/{diagram-KO2AKTUF-BKTx2iRe.js → diagram-KO2AKTUF-BrzmD5NB.js} +1 -1
  27. package/dist/client/assets/{diagram-LMA3HP47-9iEiScHT.js → diagram-LMA3HP47-BhrlgXiJ.js} +1 -1
  28. package/dist/client/assets/{diagram-OG6HWLK6-UIZRh7Qa.js → diagram-OG6HWLK6-K-fWsJ3a.js} +1 -1
  29. package/dist/client/assets/{erDiagram-TEJ5UH35-BpNJmJva.js → erDiagram-TEJ5UH35-Der6PjHE.js} +1 -1
  30. package/dist/client/assets/{flowDiagram-I6XJVG4X-C-rK0XZ1.js → flowDiagram-I6XJVG4X-BVWgGhXe.js} +1 -1
  31. package/dist/client/assets/{ganttDiagram-6RSMTGT7-DWyfPvv_.js → ganttDiagram-6RSMTGT7-DcoZ5ggj.js} +1 -1
  32. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-x71bzdc_.js → gitGraphDiagram-PVQCEYII-BhhbMTBu.js} +1 -1
  33. package/dist/client/assets/index-B6BltHSr.css +2 -0
  34. package/dist/client/assets/index-CFOYm3j9.js +276 -0
  35. package/dist/client/assets/{infoDiagram-5YYISTIA-CbRus0Xu.js → infoDiagram-5YYISTIA-Lwc-agyc.js} +1 -1
  36. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-DvaMHrgN.js → ishikawaDiagram-YF4QCWOH-B95U1Xcl.js} +1 -1
  37. package/dist/client/assets/{journeyDiagram-JHISSGLW-BQBu4YGn.js → journeyDiagram-JHISSGLW-xFpigy5D.js} +1 -1
  38. package/dist/client/assets/{kanban-definition-UN3LZRKU-8rU-U7L1.js → kanban-definition-UN3LZRKU-D3mudQnR.js} +1 -1
  39. package/dist/client/assets/{line-CSZnwjLA.js → line-DtTL3ZI2.js} +1 -1
  40. package/dist/client/assets/{mermaid-parser.core-CTOl2slE.js → mermaid-parser.core-Dau7K6zV.js} +1 -1
  41. package/dist/client/assets/{mermaid.core-B9gr0Vqf.js → mermaid.core-B8qtvATu.js} +3 -3
  42. package/dist/client/assets/{mindmap-definition-RKZ34NQL-But1_PWQ.js → mindmap-definition-RKZ34NQL-Cus04Yq3.js} +1 -1
  43. package/dist/client/assets/{pieDiagram-4H26LBE5-CnlVmfSG.js → pieDiagram-4H26LBE5-BCMGpBnn.js} +1 -1
  44. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-Dww1ZGuR.js → quadrantDiagram-W4KKPZXB-CAmOr-PJ.js} +1 -1
  45. package/dist/client/assets/{requirementDiagram-4Y6WPE33-CNf_loe8.js → requirementDiagram-4Y6WPE33-kisD3jc4.js} +1 -1
  46. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-DBhi37Jj.js → sankeyDiagram-5OEKKPKP-CsCedmM0.js} +1 -1
  47. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-B64hb4E4.js → sequenceDiagram-3UESZ5HK-B-dAi954.js} +1 -1
  48. package/dist/client/assets/{stateDiagram-AJRCARHV-DcS6oB-S.js → stateDiagram-AJRCARHV-X0BnedIW.js} +1 -1
  49. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-6B8YH8Y2.js +1 -0
  50. package/dist/client/assets/{timeline-definition-PNZ67QCA-Dq-4tXfh.js → timeline-definition-PNZ67QCA-DfFoSjhr.js} +1 -1
  51. package/dist/client/assets/{vennDiagram-CIIHVFJN-CeDklSE_.js → vennDiagram-CIIHVFJN-CKSCBwhG.js} +1 -1
  52. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-D2cJISMm.js → wardleyDiagram-YWT4CUSO-DNIBQmHO.js} +1 -1
  53. package/dist/client/assets/{xychartDiagram-2RQKCTM6-CBF-tTpF.js → xychartDiagram-2RQKCTM6-FvB55TQN.js} +1 -1
  54. package/dist/client/index.html +2 -2
  55. package/dist/server/db.js +368 -5
  56. package/dist/server/db.js.map +1 -1
  57. package/dist/server/index.js +194 -250
  58. package/dist/server/index.js.map +1 -1
  59. package/dist/server/lib/agentRuns.js +14 -1
  60. package/dist/server/lib/agentRuns.js.map +1 -1
  61. package/dist/server/lib/automationLoopProjection.js +55 -12
  62. package/dist/server/lib/automationLoopProjection.js.map +1 -1
  63. package/dist/server/lib/automationProgression.js +2 -5
  64. package/dist/server/lib/automationProgression.js.map +1 -1
  65. package/dist/server/lib/automationResumeDecision.js +19 -1
  66. package/dist/server/lib/automationResumeDecision.js.map +1 -1
  67. package/dist/server/lib/buildControlEligibility.js +4 -0
  68. package/dist/server/lib/buildControlEligibility.js.map +1 -0
  69. package/dist/server/lib/buildExecutionAdmission.js +76 -0
  70. package/dist/server/lib/buildExecutionAdmission.js.map +1 -0
  71. package/dist/server/lib/buildSequenceResume.js +79 -0
  72. package/dist/server/lib/buildSequenceResume.js.map +1 -0
  73. package/dist/server/lib/buildWorkload.js +11 -0
  74. package/dist/server/lib/buildWorkload.js.map +1 -0
  75. package/dist/server/lib/checkAutoFixDetails.js +36 -1
  76. package/dist/server/lib/checkAutoFixDetails.js.map +1 -1
  77. package/dist/server/lib/executionEnvironmentReconciliation.js +15 -2
  78. package/dist/server/lib/executionEnvironmentReconciliation.js.map +1 -1
  79. package/dist/server/lib/executionEnvironments.js +15 -0
  80. package/dist/server/lib/executionEnvironments.js.map +1 -1
  81. package/dist/server/lib/executionRetry.js +13 -1
  82. package/dist/server/lib/executionRetry.js.map +1 -1
  83. package/dist/server/lib/executionRunAuthority.js +2 -2
  84. package/dist/server/lib/executionRunAuthority.js.map +1 -1
  85. package/dist/server/lib/executionTargets.js +7 -4
  86. package/dist/server/lib/executionTargets.js.map +1 -1
  87. package/dist/server/lib/executionTimeline.js +8 -13
  88. package/dist/server/lib/executionTimeline.js.map +1 -1
  89. package/dist/server/lib/executionTimelineHierarchy.js +83 -0
  90. package/dist/server/lib/executionTimelineHierarchy.js.map +1 -0
  91. package/dist/server/lib/failedBuildSequenceRecovery.js +133 -0
  92. package/dist/server/lib/failedBuildSequenceRecovery.js.map +1 -0
  93. package/dist/server/lib/hostRunSession.js +62 -0
  94. package/dist/server/lib/hostRunSession.js.map +1 -0
  95. package/dist/server/lib/hostServiceRecovery.js +159 -0
  96. package/dist/server/lib/hostServiceRecovery.js.map +1 -0
  97. package/dist/server/lib/hostServiceRunProvider.js +32 -0
  98. package/dist/server/lib/hostServiceRunProvider.js.map +1 -0
  99. package/dist/server/lib/mobileAccess.js +6 -2
  100. package/dist/server/lib/mobileAccess.js.map +1 -1
  101. package/dist/server/lib/projectAutoConfig.js +5 -2
  102. package/dist/server/lib/projectAutoConfig.js.map +1 -1
  103. package/dist/server/lib/projectTargets.js +16 -2
  104. package/dist/server/lib/projectTargets.js.map +1 -1
  105. package/dist/server/lib/projects.js +25 -1
  106. package/dist/server/lib/projects.js.map +1 -1
  107. package/dist/server/lib/reviewFindingReconciliation.js +9 -2
  108. package/dist/server/lib/reviewFindingReconciliation.js.map +1 -1
  109. package/dist/server/lib/reviewFindings.js +82 -21
  110. package/dist/server/lib/reviewFindings.js.map +1 -1
  111. package/dist/server/lib/reviewRepairAssessmentRecords.js +41 -0
  112. package/dist/server/lib/reviewRepairAssessmentRecords.js.map +1 -0
  113. package/dist/server/lib/reviewRepairCompletion.js +78 -18
  114. package/dist/server/lib/reviewRepairCompletion.js.map +1 -1
  115. package/dist/server/lib/reviewRepairIterationRecords.js +4 -2
  116. package/dist/server/lib/reviewRepairIterationRecords.js.map +1 -1
  117. package/dist/server/lib/reviewRepairIterations.js +8 -2
  118. package/dist/server/lib/reviewRepairIterations.js.map +1 -1
  119. package/dist/server/lib/reviewRepairProgress.js +177 -0
  120. package/dist/server/lib/reviewRepairProgress.js.map +1 -0
  121. package/dist/server/lib/reviewRepairReconciliation.js +119 -140
  122. package/dist/server/lib/reviewRepairReconciliation.js.map +1 -1
  123. package/dist/server/lib/reviewRepairResumeOverride.js +55 -0
  124. package/dist/server/lib/reviewRepairResumeOverride.js.map +1 -0
  125. package/dist/server/lib/run.js +541 -504
  126. package/dist/server/lib/run.js.map +1 -1
  127. package/dist/server/lib/runProcessIdentity.js +71 -0
  128. package/dist/server/lib/runProcessIdentity.js.map +1 -0
  129. package/dist/server/lib/runProcesses.js +273 -0
  130. package/dist/server/lib/runProcesses.js.map +1 -0
  131. package/dist/server/lib/runServices.js +223 -0
  132. package/dist/server/lib/runServices.js.map +1 -0
  133. package/dist/server/lib/runSessionLifecycle.js +77 -0
  134. package/dist/server/lib/runSessionLifecycle.js.map +1 -0
  135. package/dist/server/lib/runStatus.js +8 -0
  136. package/dist/server/lib/runStatus.js.map +1 -0
  137. package/dist/server/lib/serviceRunCleanup.js +70 -0
  138. package/dist/server/lib/serviceRunCleanup.js.map +1 -0
  139. package/dist/server/lib/serviceRuns.js +458 -19
  140. package/dist/server/lib/serviceRuns.js.map +1 -1
  141. package/dist/server/lib/ticketAutomation.js +4 -27
  142. package/dist/server/lib/ticketAutomation.js.map +1 -1
  143. package/dist/server/lib/ticketRunOperations.js +103 -34
  144. package/dist/server/lib/ticketRunOperations.js.map +1 -1
  145. package/dist/server/lib/tickets.js +0 -13
  146. package/dist/server/lib/tickets.js.map +1 -1
  147. package/dist/server/lib/types.js.map +1 -1
  148. package/dist/server/workers/build.js +44 -69
  149. package/dist/server/workers/build.js.map +1 -1
  150. package/dist/server/workers/plan.js +0 -7
  151. package/dist/server/workers/plan.js.map +1 -1
  152. package/dist/server/workers/review.js +95 -146
  153. package/dist/server/workers/review.js.map +1 -1
  154. package/package.json +1 -1
  155. package/dist/client/assets/ActivityView-CKvbDXeA.js +0 -1
  156. package/dist/client/assets/GitHubActionsDialog-Dzo0vtak.js +0 -1
  157. package/dist/client/assets/VerificationDialog-BJnOitrJ.js +0 -4
  158. package/dist/client/assets/channel-5mIy7nm1.js +0 -1
  159. package/dist/client/assets/classDiagram-4FO5ZUOK-BiQ-X2Sg.js +0 -1
  160. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-CF-wCYW-.js +0 -1
  161. package/dist/client/assets/index-CIAO5aE_.css +0 -2
  162. package/dist/client/assets/index-nCGyalrn.js +0 -276
  163. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-PWeeL0tR.js +0 -1
  164. package/dist/server/lib/automationDeliveryDecision.js +0 -34
  165. package/dist/server/lib/automationDeliveryDecision.js.map +0 -1
@@ -12,7 +12,7 @@ import { resolveReviewerConfig } from '../lib/reviewerConfig.js';
12
12
  import { enqueue, isRunning } from '../lib/queue.js';
13
13
  import { appendLifecycleEvent, getExecutionRun, transitionExecutionRun, withExecutionRunTransaction } from '../lib/executionRuns.js';
14
14
  import { buildReviewContext } from '../lib/reviewContext.js';
15
- import { computeDiffSignature, constrainReviewOutputToDiff, createReviewRun, finalizeReviewRun, formatExistingReviewFindingsForPrompt, formatReviewFindingsMarkdown, getLatestCompletedReviewRunForContext, hasPriorReviewRunForBundle, insertReviewFindings, listReviewFindings, mergeReviewFindings, parseStructuredReviewOutput, reconcileReviewFindingsToDiff, updateReviewRunPreparation, } from '../lib/reviewFindings.js';
15
+ import { computeDiffSignature, computeReviewEvaluatorFingerprint, constrainReviewOutputToDiff, createReviewRun, finalizeReviewRun, formatExistingReviewFindingsForPrompt, formatReviewFindingsMarkdown, getLatestCompletedReviewRunForContext, hasPriorReviewRunForBundle, insertReviewFindings, listReviewFindings, mergeReviewFindings, parseStructuredReviewOutput, reconcileReviewFindingsToDiff, updateReviewRunPreparation, } from '../lib/reviewFindings.js';
16
16
  import { buildSpecCoverageContext } from '../lib/specCoverageContext.js';
17
17
  import { listTickets } from '../lib/tickets.js';
18
18
  import { registerBundleActivity, unregisterBundleActivity } from '../lib/bundleActivity.js';
@@ -23,12 +23,12 @@ import { captureStageBaseline, captureStageSuccess } from '../lib/ticketUndo.js'
23
23
  import { beginTicketThinkingRun, bindTicketThinkingMessage } from '../lib/thinkingState.js';
24
24
  import { autoParkTicketIfStale, getTicket, resolveTicketBranch, resolveTicketTool, resolveTicketWorkerKey } from '../lib/tickets.js';
25
25
  import { createAgentRun, emitAgentRunsUpdated, emitExecutionAgentRunsUpdated, getAgentRun, listAgentRunsForExecutionRun, terminalizeAgentRunsForExecutionRun, } from '../lib/agentRuns.js';
26
- import { buildAutomationFixInstruction, buildAutomationFixStatusMessage, countBlockingFindings, decideReviewAutomation, depthAtLeast, getBundleAutomationState, markBundleAutomationDeliveryReady, resetBundleAutomationLoop, resolveAutomationConfig, } from '../lib/ticketAutomation.js';
26
+ import { buildAutomationFixInstruction, buildAutomationFixStatusMessage, depthAtLeast, resetBundleAutomationLoop, resolveAutomationConfig, } from '../lib/ticketAutomation.js';
27
27
  import { runAutomationCommitChain } from '../lib/ticketAutomationCommit.js';
28
28
  import { submitTicketFollowUp } from '../lib/ticketFollowUpOperations.js';
29
- import { completeAutomationProgressionInTransaction, completeAutomationProgression, completeAutomationReviewFixActionInTransaction, createAutomationReviewFixInTransaction, ensureAutomationProgression, finishAutomationReviewFix, pauseAutomationProgression, resolveProgressionForChild, waitAutomationProgression, } from '../lib/automationProgression.js';
29
+ import { completeAutomationProgressionInTransaction, completeAutomationProgression, completeAutomationReviewFixActionInTransaction, ensureAutomationProgression, finishAutomationReviewFix, pauseAutomationProgression, resolveProgressionForChild, waitAutomationProgression, } from '../lib/automationProgression.js';
30
30
  import { assertAutomationAuthorizationCurrent, assertAutomationBoundaryNotRequired, AutomationCheckGateError, } from '../lib/automationCheckGate.js';
31
- import { attachReviewRepairActionEnvelopeInTransaction, attachReviewRepairActionInTransaction, appendReviewRepairIterationDecisionInTransaction, attachReviewRepairResultInTransaction, claimReviewRepairIterationInTransaction, getReviewRepairIteration, getReviewRepairIterationByVerification, pauseReviewRepairIteration, pauseReviewRepairIterationInTransaction, terminalizeReviewRepairIterationInTransaction, } from '../lib/reviewRepairIterations.js';
31
+ import { attachReviewRepairActionInTransaction, attachReviewRepairResultInTransaction, getReviewRepairIteration, getReviewRepairIterationByVerification, pauseReviewRepairIteration, terminalizeReviewRepairIterationInTransaction, } from '../lib/reviewRepairIterations.js';
32
32
  import { formatBuildOpenQuestionAnswersPrompt, listAnsweredBuildOpenQuestionsForBundle } from '../lib/buildOpenQuestions.js';
33
33
  import { validateWorkflowContext } from '../lib/types.js';
34
34
  import { isModelResolutionError } from '../lib/modelResolutionErrors.js';
@@ -97,6 +97,11 @@ const stripSystemReminderBlocks = (output) => {
97
97
  const normalizeReviewOutput = (output) => {
98
98
  return extractProjectMemorySuggestionsFromOutput(stripSystemReminderBlocks(output));
99
99
  };
100
+ const getEffectiveReviewOutputProvenance = (outputs) => {
101
+ const provenances = outputs.map(output => output.outputProvenance ?? 'parse_failed');
102
+ return ['parse_failed', 'markdown_fallback', 'subagent_aggregation', 'structured_transcript', 'structured_primary']
103
+ .find(provenance => provenances.includes(provenance)) ?? 'parse_failed';
104
+ };
100
105
  const resolveStructuredReviewOutput = (parentResponse, transcriptRuns, mainRole = 'code-review') => {
101
106
  const normalizedParent = typeof parentResponse === 'string'
102
107
  ? normalizeReviewOutput(parentResponse)
@@ -114,7 +119,7 @@ const resolveStructuredReviewOutput = (parentResponse, transcriptRuns, mainRole
114
119
  if (!normalized.cleanedOutput) {
115
120
  return [];
116
121
  }
117
- const parsed = parseStructuredReviewOutput(normalized.cleanedOutput);
122
+ const parsed = parseStructuredReviewOutput(normalized.cleanedOutput, 'structured_transcript');
118
123
  return parsed.status === 'completed' ? [parsed] : [];
119
124
  })
120
125
  .at(0);
@@ -129,7 +134,7 @@ const resolveStructuredReviewOutput = (parentResponse, transcriptRuns, mainRole
129
134
  if (!normalized.cleanedOutput) {
130
135
  return [];
131
136
  }
132
- const parsed = parseStructuredReviewOutput(normalized.cleanedOutput);
137
+ const parsed = parseStructuredReviewOutput(normalized.cleanedOutput, 'subagent_aggregation');
133
138
  return parsed.status === 'completed' ? [parsed] : [];
134
139
  });
135
140
  if (parsedSubagentOutputs.length === 0) {
@@ -148,12 +153,18 @@ const resolveStructuredReviewOutput = (parentResponse, transcriptRuns, mainRole
148
153
  findings,
149
154
  resolvedExistingFindingIds: [],
150
155
  status: 'completed',
156
+ outputProvenance: parsedSubagentOutputs.some(output => output.outputProvenance === 'markdown_fallback')
157
+ ? 'markdown_fallback'
158
+ : 'subagent_aggregation',
151
159
  },
152
160
  };
153
161
  };
154
162
  const MAX_INLINE_DIFF_LINES = 400;
155
163
  const MAX_INLINE_DIFF_CHARS = 20_000;
156
164
  const SUBAGENT_REVIEW_GUIDANCE = 'If you delegate any part of the review to subagents, you remain responsible for evaluating their results and consolidating every accepted finding into your final response using the exact format below.';
165
+ const REVIEW_PROMPT_VERSION = 'ticket-review-v2';
166
+ const REVIEW_ROLE_POLICY_VERSION = 'ticket-review-role-policy-v1';
167
+ const REVIEW_OUTPUT_CONTRACT_VERSION = 'archon-review-findings-v1';
157
168
  const countLines = (value) => {
158
169
  if (!value) {
159
170
  return 0;
@@ -372,89 +383,23 @@ Every finding must set \`file_path\` to a path in \`<review_scope>\` and set at
372
383
 
373
384
  Do not include planning text, implementation steps, or commentary about changing modes.`, ticket.skills);
374
385
  };
375
- const runReviewCompletionAutomation = async (ticket, project, reviewRunId, parsedStatus, findings, io, executionContext, initiation, persistedAutomation) => {
376
- if (!ticket.worktree_bundle_id || !ticket.project_id) {
386
+ const runReviewCompletionAutomation = async (ticket, project, reviewRunId, io, executionContext, initiation, persistedAutomation) => {
387
+ if (!ticket.worktree_bundle_id || !ticket.project_id || !persistedAutomation) {
377
388
  return false;
378
389
  }
379
390
  const projectId = ticket.project_id;
380
391
  const bundleId = ticket.worktree_bundle_id;
381
- const liveTicket = getTicket(ticket.id) ?? ticket;
382
- const liveProject = getEffectiveProject(liveTicket) ?? project;
383
- const config = persistedAutomation?.config ?? resolveAutomationConfig(liveTicket.bundle ?? null, liveProject);
384
- const bundleState = getBundleAutomationState(projectId, bundleId);
385
- const decision = persistedAutomation?.decision
386
- ?? decideReviewAutomation(config, bundleState, reviewRunId, parsedStatus, findings);
387
- const progressionRunId = persistedAutomation?.progressionRunId
388
- ?? (initiation.initiator === 'automation'
389
- ? resolveProgressionForChild({ projectId, bundleId, childRunId: executionContext.runId }).id
390
- : null);
392
+ const { config, decision, progressionRunId, disposition } = persistedAutomation;
391
393
  const progression = progressionRunId ? { id: progressionRunId } : null;
392
- if (progression) {
393
- const iteration = getReviewRepairIterationByVerification(projectId, executionContext.runId);
394
- if (iteration?.phase === 'verification_active'
395
- && iteration.resulting_review_execution_run_id === executionContext.runId) {
396
- const resultingBlockingCount = parsedStatus === 'completed'
397
- ? countBlockingFindings(findings, config)
398
- : null;
399
- withExecutionRunTransaction(transaction => {
400
- if (parsedStatus === 'completed' && reviewRunId) {
401
- attachReviewRepairResultInTransaction(transaction, {
402
- projectId,
403
- iterationId: iteration.id,
404
- expectedPhase: 'verification_active',
405
- expectedVerificationRunId: executionContext.runId,
406
- resultingReviewRunId: reviewRunId,
407
- });
408
- }
409
- appendReviewRepairIterationDecisionInTransaction(transaction, {
410
- projectId,
411
- iterationId: iteration.id,
412
- decisionPoint: 'verification_completion',
413
- effectiveAutomationConfig: config,
414
- decisionCode: parsedStatus === 'completed' ? 'verification_completed' : 'verification_failed',
415
- operationRunId: executionContext.runId,
416
- });
417
- const terminal = decision.kind === 'fix_iteration'
418
- ? { outcome: 'continuing', stopReason: null }
419
- : decision.kind === 'clean'
420
- ? { outcome: 'repaired', stopReason: 'no_blocking_findings' }
421
- : decision.kind === 'exhausted'
422
- ? { outcome: 'exhausted', stopReason: 'max_iterations' }
423
- : decision.kind === 'pause_blocking'
424
- ? { outcome: 'interrupted', stopReason: 'automation_disabled' }
425
- : parsedStatus !== 'completed'
426
- ? { outcome: 'failed', stopReason: 'verification_failed' }
427
- : { outcome: 'interrupted', stopReason: 'configuration_changed' };
428
- if (parsedStatus !== 'completed') {
429
- pauseReviewRepairIterationInTransaction(transaction, {
430
- projectId,
431
- iterationId: iteration.id,
432
- expectedPhase: 'verification_active',
433
- expectedCurrentRunId: executionContext.runId,
434
- stopReason: 'verification_failed',
435
- });
436
- }
437
- else {
438
- terminalizeReviewRepairIterationInTransaction(transaction, {
439
- projectId,
440
- iterationId: iteration.id,
441
- expectedPhase: 'verification_active',
442
- expectedCurrentRunId: executionContext.runId,
443
- outcome: terminal.outcome,
444
- stopReason: terminal.stopReason,
445
- resultingBlockingCount,
446
- });
447
- if (decision.kind === 'exhausted' && progression) {
448
- completeAutomationProgressionInTransaction(transaction, {
449
- projectId,
450
- bundleId,
451
- progressionRunId: progression.id,
452
- deliveryReadyStageRunId: executionContext.runId,
453
- });
454
- }
455
- }
456
- }, asGenericEmitter(io), 'immediate');
394
+ if (disposition === 'handled' || decision.kind === 'no_progress') {
395
+ return true;
396
+ }
397
+ if (disposition === 'commit') {
398
+ if (!progressionRunId) {
399
+ throw new Error('Persisted Review commit has no owning progression');
457
400
  }
401
+ await runAutomationCommitChain(ticket, project, ticket.bundle ?? null, config, io, progressionRunId, undefined, executionContext.runId);
402
+ return true;
458
403
  }
459
404
  switch (decision.kind) {
460
405
  case 'manual':
@@ -511,61 +456,14 @@ const runReviewCompletionAutomation = async (ticket, project, reviewRunId, parse
511
456
  review_finding_run_id: reviewRunId,
512
457
  review_severity: config.reviewSeverity,
513
458
  });
514
- const repairProgressionRunId = progression?.id ?? ensureAutomationProgression({
515
- projectId,
516
- bundleId,
517
- ticketId: ticket.id,
518
- ticketTitle: ticket.title,
519
- parentRunId: executionContext.runId,
520
- workflowContext: initiation.workflowContext,
521
- broadcaster: asGenericEmitter(io),
522
- }).runId;
523
- let reviewFix = persistedAutomation?.repair?.reviewFix ?? null;
524
- let iterationId = persistedAutomation?.repair?.iterationId ?? null;
525
- if (persistedAutomation && !persistedAutomation.repair) {
459
+ if (disposition !== 'dispatch_repair' || !persistedAutomation.repair) {
526
460
  return true;
527
461
  }
528
- if (!reviewFix) {
529
- const claimed = withExecutionRunTransaction(transaction => {
530
- const iteration = claimReviewRepairIterationInTransaction(transaction, {
531
- projectId,
532
- worktreeBundleId: bundleId,
533
- ownerTicketId: ticket.id,
534
- automationProgressionRunId: repairProgressionRunId,
535
- triggeringReviewExecutionRunId: executionContext.runId,
536
- triggeringReviewRunId: reviewRunId,
537
- triggeringBlockingCount: countBlockingFindings(findings, config),
538
- effectiveAutomationConfig: config,
539
- decisionCode: 'repair_admitted',
540
- });
541
- if (iteration.phase !== 'observed') {
542
- return { iteration, reviewFix: null };
543
- }
544
- const createdReviewFix = createAutomationReviewFixInTransaction(transaction, {
545
- projectId,
546
- bundleId,
547
- ticketId: ticket.id,
548
- ticketTitle: ticket.title,
549
- progressionRunId: repairProgressionRunId,
550
- workflowContext: reviewFixWorkflowContext,
551
- triggeringReviewRunId: executionContext.runId,
552
- reviewFindingRunId: reviewRunId,
553
- reviewSeverity: config.reviewSeverity,
554
- });
555
- attachReviewRepairActionEnvelopeInTransaction(transaction, {
556
- projectId,
557
- iterationId: iteration.id,
558
- expectedPhase: 'observed',
559
- runId: createdReviewFix.runId,
560
- });
561
- return { iteration, reviewFix: createdReviewFix };
562
- }, asGenericEmitter(io), 'immediate');
563
- iterationId = claimed.iteration.id;
564
- reviewFix = claimed.reviewFix;
565
- }
566
- if (!reviewFix) {
567
- return true;
462
+ const { reviewFix, iterationId } = persistedAutomation.repair;
463
+ if (!progressionRunId) {
464
+ throw new Error('Persisted Review repair has no owning progression');
568
465
  }
466
+ const repairProgressionRunId = progressionRunId;
569
467
  const started = submitTicketFollowUp({
570
468
  ticketId: ticket.id,
571
469
  requestedProjectId: projectId,
@@ -580,7 +478,7 @@ const runReviewCompletionAutomation = async (ticket, project, reviewRunId, parse
580
478
  onExecutionCreated: (createdContext, transaction) => {
581
479
  attachReviewRepairActionInTransaction(transaction, {
582
480
  projectId,
583
- iterationId: iterationId,
481
+ iterationId,
584
482
  expectedPhase: 'action_claimed',
585
483
  runId: createdContext.runId,
586
484
  });
@@ -674,8 +572,28 @@ const runReviewCompletionAutomation = async (ticket, project, reviewRunId, parse
674
572
  return true;
675
573
  }
676
574
  case 'exhausted': {
677
- if (!progression) {
678
- markBundleAutomationDeliveryReady(projectId, bundleId, executionContext.runId);
575
+ if (progression) {
576
+ waitAutomationProgression({
577
+ projectId,
578
+ bundleId,
579
+ progressionRunId: progression.id,
580
+ pauseCode: 'review',
581
+ pauseReason: 'Blocking Review findings remain after repair verification.',
582
+ reasonCode: 'precondition_failed',
583
+ pausedStageRunId: executionContext.runId,
584
+ broadcaster: asGenericEmitter(io),
585
+ });
586
+ }
587
+ else {
588
+ pauseAutomationProgression({
589
+ projectId,
590
+ bundleId,
591
+ pauseCode: 'review',
592
+ pauseReason: 'Blocking Review findings remain after repair verification.',
593
+ reasonCode: 'precondition_failed',
594
+ pausedStageRunId: null,
595
+ broadcaster: asGenericEmitter(io),
596
+ });
679
597
  }
680
598
  const pausedTicket = getTicket(ticket.id);
681
599
  if (pausedTicket) {
@@ -938,6 +856,16 @@ export function startReview(ticket, io, options) {
938
856
  model: acceptedReviewExecution.model,
939
857
  variant: acceptedReviewExecution.variant,
940
858
  };
859
+ const evaluatorInput = {
860
+ tool,
861
+ ...reviewerConfig,
862
+ skills,
863
+ promptVersion: REVIEW_PROMPT_VERSION,
864
+ rolePolicyVersion: REVIEW_ROLE_POLICY_VERSION,
865
+ outputContractVersion: REVIEW_OUTPUT_CONTRACT_VERSION,
866
+ rolePolicy: 'preparing',
867
+ changeScope: null,
868
+ };
941
869
  reviewExecutionProvenance = { tool, model: reviewerConfig.model, variant: reviewerConfig.variant };
942
870
  const reviewProcessState = registerReviewProcess(acceptedTicket.id);
943
871
  registeredReviewProcess = reviewProcessState;
@@ -1112,6 +1040,7 @@ export function startReview(ticket, io, options) {
1112
1040
  messageId: null,
1113
1041
  model: reviewerConfig.model,
1114
1042
  variant: reviewerConfig.variant,
1043
+ evaluatorFingerprint: computeReviewEvaluatorFingerprint(evaluatorInput),
1115
1044
  status: 'running',
1116
1045
  });
1117
1046
  transaction.addExecutionRunLink({
@@ -1181,13 +1110,15 @@ export function startReview(ticket, io, options) {
1181
1110
  const supplementalRequirements = ticket.project_id && ticket.worktree_bundle_id
1182
1111
  ? formatBuildOpenQuestionAnswersPrompt(listAnsweredBuildOpenQuestionsForBundle(ticket.project_id, ticket.worktree_bundle_id))
1183
1112
  : '';
1184
- const previousCompletedReviewRun = getLatestCompletedReviewRunForContext({
1185
- ticketId: ticket.id,
1186
- projectId: ticket.project_id,
1187
- worktreeBundleId: ticket.worktree_bundle_id,
1188
- });
1189
- const existingReviewFindings = previousCompletedReviewRun
1190
- ? reconcileReviewFindingsToDiff(listReviewFindings(previousCompletedReviewRun.id), diffText)
1113
+ const previousReviewRunId = verificationIteration
1114
+ ? verificationIteration.triggering_review_run_id
1115
+ : getLatestCompletedReviewRunForContext({
1116
+ ticketId: ticket.id,
1117
+ projectId: ticket.project_id,
1118
+ worktreeBundleId: ticket.worktree_bundle_id,
1119
+ })?.id;
1120
+ const existingReviewFindings = previousReviewRunId
1121
+ ? reconcileReviewFindingsToDiff(listReviewFindings(previousReviewRunId), diffText)
1191
1122
  : [];
1192
1123
  const specCoverageEligible = Boolean(project.spec_aware_code_review_enabled)
1193
1124
  && Boolean(ticket.origin_spec_snapshot_id)
@@ -1204,6 +1135,14 @@ export function startReview(ticket, io, options) {
1204
1135
  }
1205
1136
  const runSpecCoverage = Boolean(specContext) && !hasPriorReview;
1206
1137
  const specGuardContext = hasPriorReview ? specContext : null;
1138
+ const preparedEvaluatorInput = {
1139
+ ...evaluatorInput,
1140
+ rolePolicy: runSpecCoverage ? 'code-review+spec-coverage' : specGuardContext ? 'code-review+spec-guard' : 'code-review',
1141
+ changeScope,
1142
+ };
1143
+ const evaluatorFingerprint = computeReviewEvaluatorFingerprint(preparedEvaluatorInput);
1144
+ db.prepare('UPDATE review_runs SET evaluator_fingerprint = ? WHERE id = ? AND status = ?')
1145
+ .run(evaluatorFingerprint, activeReviewRunId, 'running');
1207
1146
  let specCoverageRunStreamTarget = null;
1208
1147
  if (runSpecCoverage) {
1209
1148
  const runId = createAgentRun({
@@ -1338,11 +1277,16 @@ export function startReview(ticket, io, options) {
1338
1277
  let persistedMessageId = null;
1339
1278
  let reviewContent = null;
1340
1279
  let findingsToPersist = [];
1280
+ let outputProvenance = constrainedBlindParsed?.outputProvenance ?? 'parse_failed';
1341
1281
  if (constrainedBlindParsed?.status === 'completed') {
1342
1282
  const specOutput = resolveStructuredReviewOutput(specCoverageResult?.response ?? null, specCoverageResult?.transcriptRuns ?? [], 'spec-coverage').parsed;
1343
1283
  const specParsed = specOutput
1344
1284
  ? constrainReviewOutputToDiff(specOutput, diffText)
1345
1285
  : null;
1286
+ outputProvenance = getEffectiveReviewOutputProvenance([
1287
+ constrainedBlindParsed,
1288
+ ...(specParsed?.status === 'completed' ? [specParsed] : []),
1289
+ ]);
1346
1290
  const newlyReportedFindings = specParsed && specParsed.status === 'completed'
1347
1291
  ? [...constrainedBlindParsed.findings, ...specParsed.findings.map(finding => ({
1348
1292
  ...finding,
@@ -1353,11 +1297,15 @@ export function startReview(ticket, io, options) {
1353
1297
  existingFindings: existingReviewFindings,
1354
1298
  newFindings: newlyReportedFindings,
1355
1299
  resolvedExistingFindingIds: constrainedBlindParsed.resolvedExistingFindingIds,
1300
+ outputProvenance,
1301
+ evaluatorFingerprint,
1356
1302
  });
1357
1303
  const blindFindings = mergeReviewFindings({
1358
1304
  existingFindings: existingReviewFindings,
1359
1305
  newFindings: constrainedBlindParsed.findings,
1360
1306
  resolvedExistingFindingIds: constrainedBlindParsed.resolvedExistingFindingIds,
1307
+ outputProvenance: constrainedBlindParsed.outputProvenance ?? 'parse_failed',
1308
+ evaluatorFingerprint,
1361
1309
  });
1362
1310
  parsedFindings = mergedFindings;
1363
1311
  parsedStatus = constrainedBlindParsed.status;
@@ -1393,6 +1341,7 @@ export function startReview(ticket, io, options) {
1393
1341
  status: parsedStatus ?? 'parse_failed',
1394
1342
  messageId,
1395
1343
  failureMessage: parseFailed ? 'Review output could not be parsed' : null,
1344
+ outputProvenance,
1396
1345
  });
1397
1346
  if (findingsToPersist.length > 0) {
1398
1347
  insertReviewFindings(activeReviewRunId, findingsToPersist);
@@ -1460,7 +1409,7 @@ export function startReview(ticket, io, options) {
1460
1409
  let handled = false;
1461
1410
  try {
1462
1411
  await releaseWorkloadEnvironment();
1463
- handled = await runReviewCompletionAutomation(updated, project, reviewRunId, parsedStatus, parsedFindings, io, executionContext, initiation, persisted.persistedAutomation);
1412
+ handled = await runReviewCompletionAutomation(updated, project, reviewRunId, io, executionContext, initiation, persisted.persistedAutomation);
1464
1413
  }
1465
1414
  catch (automationError) {
1466
1415
  if (ticket.project_id && ticket.worktree_bundle_id) {