@straiffi/archon 1.7.5 → 1.7.6
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.
- package/dist/client/assets/{ActivityView-CT9iCPyc.js → ActivityView-BrZY8vYf.js} +1 -1
- package/dist/client/assets/{GitHubActionsDialog-BA6xyQeX.js → GitHubActionsDialog-CUfdVw97.js} +1 -1
- package/dist/client/assets/{TestsDialog-D2qrW5Ug.js → TestsDialog-FXcnLOyf.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-R6v7w0Nl.js → architectureDiagram-3BPJPVTR-D0PXGvSL.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-CHlBlnJq.js → blockDiagram-GPEHLZMM-BCLAxnp5.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-BvZKqUc6.js → c4Diagram-AAUBKEIU-DVZ5yZWV.js} +1 -1
- package/dist/client/assets/channel-BCPCrThZ.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-2gsIkBeO.js → chunk-2J33WTMH-BGJYj1Lu.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-CcqPBjqx.js → chunk-3OPIFGDE-DI5-yK3m.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-DX_wK5Rp.js → chunk-5ZQYHXKU-Dnr5DDsb.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-B9WUxzJL.js → chunk-727SXJPM-8HdFwn-P.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-BG0s75_H.js → chunk-AQP2D5EJ-C7x9t2uJ.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-CyNcvvqW.js → chunk-CSCIHK7Q-CrhwRPh5.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-CWVy_Wi0.js → chunk-KSCS5N6A-CdD62r5U.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-3dsXRB0X.js → chunk-L5ZTLDWV-CqQVvwc_.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-B09QSB9z.js → chunk-LZXEDZCA-DLHrqoJ4.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-BxzAdxTN.js → chunk-ND2GUHAM-B0yOdiPF.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-D4ZfFwbB.js → chunk-NZK2D7GU-boM-MocY.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-BxQULuKS.js → chunk-O5CBEL6O-B0jgJn0t.js} +1 -1
- package/dist/client/assets/{chunk-WU5MYG2G-CEJwp0Ry.js → chunk-WU5MYG2G-C_S_v-m2.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BdJlc_1i.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Bidw5Zc1.js +1 -0
- package/dist/client/assets/{dagre-BM42HDAG-Dx_V7OMy.js → dagre-BM42HDAG-DKl6Y8ya.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-Cc3VTg9P.js → diagram-2AECGRRQ-6Lyn9DBp.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-mJ1xhs2G.js → diagram-5GNKFQAL-wdS1vEkN.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-CLyT9ac8.js → diagram-KO2AKTUF-CPih29jF.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-CVr47yij.js → diagram-LMA3HP47-Cr5Px74d.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-Dp5TJ8lM.js → diagram-OG6HWLK6-i0PjSScd.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-BBxwyu0r.js → erDiagram-TEJ5UH35-Dt4yOC9J.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-CuFYzVQ-.js → flowDiagram-I6XJVG4X-Bf6kvajC.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-aRQarcQY.js → ganttDiagram-6RSMTGT7-DgxePMk_.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-B3mHSkBv.js → gitGraphDiagram-PVQCEYII-BZq2cmFS.js} +1 -1
- package/dist/client/assets/{index-Oz0S7bcT.js → index-CjRMYO1U.js} +67 -67
- package/dist/client/assets/{infoDiagram-5YYISTIA-BSyryQJ9.js → infoDiagram-5YYISTIA-Chij69KN.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-BAGbrtSG.js → ishikawaDiagram-YF4QCWOH-3qHCLFgD.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-CDTht6k6.js → journeyDiagram-JHISSGLW-DvRW8tbA.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-BDtuMp0H.js → kanban-definition-UN3LZRKU-DjR2T5I1.js} +1 -1
- package/dist/client/assets/{line-n0aNicmA.js → line-B9OzrQ1Y.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-CdE4vZ4k.js → mermaid-parser.core-DYcDor4d.js} +1 -1
- package/dist/client/assets/{mermaid.core-C546CQj1.js → mermaid.core-DG8QYo2u.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-BwO779am.js → mindmap-definition-RKZ34NQL-f4QPF6b3.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-DU1k71kn.js → pieDiagram-4H26LBE5-CMkl2jBu.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-CvM5lyQg.js → quadrantDiagram-W4KKPZXB-BXaUHzJi.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-DDBdSq0B.js → requirementDiagram-4Y6WPE33-B-Inuj_6.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-ELM2mu81.js → sankeyDiagram-5OEKKPKP-BjsmZFYI.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-D7uF-nRR.js → sequenceDiagram-3UESZ5HK-B1PAm6sX.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-IhaGRCbG.js → stateDiagram-AJRCARHV-pLONNEN8.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-kWPDF3wr.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-zHJGFvZ8.js → timeline-definition-PNZ67QCA-BLMkSXo_.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-EG1HFfD7.js → vennDiagram-CIIHVFJN-CEwGRegG.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DdQevxXg.js → wardleyDiagram-YWT4CUSO-_md2IBXC.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-BjihNG0E.js → xychartDiagram-2RQKCTM6-DVzwfXHc.js} +1 -1
- package/dist/client/index.html +1 -1
- package/dist/server/index.js +62 -76
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/automationResumeDecision.js +141 -0
- package/dist/server/lib/automationResumeDecision.js.map +1 -0
- package/dist/server/lib/buildSequences.js +27 -0
- package/dist/server/lib/buildSequences.js.map +1 -1
- package/dist/server/lib/ticketFollowUpOperations.js +19 -15
- package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
- package/dist/server/lib/ticketUndo.js +83 -31
- package/dist/server/lib/ticketUndo.js.map +1 -1
- package/dist/server/lib/tickets.js +67 -6
- package/dist/server/lib/tickets.js.map +1 -1
- package/dist/server/lib/types.js.map +1 -1
- package/dist/server/workers/review.js +1 -0
- package/dist/server/workers/review.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/channel-Ckv8cPSf.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-B-N-arsi.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-PTX7YrlL.js +0 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-ceHFQMIT.js +0 -1
package/dist/server/index.js
CHANGED
|
@@ -49,8 +49,9 @@ import { formatBuildOpenQuestionAnswersPrompt, getLatestBuildOpenQuestionBatchSt
|
|
|
49
49
|
import { acceptBuildOpenQuestionResolution } from './lib/buildOpenQuestionOperations.js';
|
|
50
50
|
import { completeAutomationProgression, createAutomationReviewFix, finishAutomationReviewFix, getAutomationProgression, recoverLegacyAutomationProgression, recoverStoppedSideEffectProgression, runAutomationProgression, stopAutomationProgression, waitAutomationProgression } from './lib/automationProgression.js';
|
|
51
51
|
import { reconcileAutomationStage } from './lib/automationReconciliation.js';
|
|
52
|
+
import { pausedRunBelongsToProgression, resolveAutomationResumeDecision } from './lib/automationResumeDecision.js';
|
|
52
53
|
import { getAutomationStageDetails, } from './lib/automationStageDetails.js';
|
|
53
|
-
import { clearAutomationPause, countBlockingFindings, depthAtLeast, getBundleAutomationState, isAutomationDepth, recordAutomationPause, resolveAutomationConfig, upsertBundleAutomationState, } from './lib/ticketAutomation.js';
|
|
54
|
+
import { buildAutomationFixInstruction, clearAutomationPause, countBlockingFindings, depthAtLeast, getBundleAutomationState, isAutomationDepth, recordAutomationPause, resolveAutomationConfig, upsertBundleAutomationState, } from './lib/ticketAutomation.js';
|
|
54
55
|
import { runAutomationCommitChain } from './lib/ticketAutomationCommit.js';
|
|
55
56
|
import { getDiscoveredSkills, normalizeSkillNames } from './lib/skills.js';
|
|
56
57
|
import { clearAllPreviewProxies } from './lib/previewProxy.js';
|
|
@@ -3954,25 +3955,6 @@ app.post('/bundles/:id/follow-up', (req, res) => {
|
|
|
3954
3955
|
});
|
|
3955
3956
|
const AUTOMATION_SIDE_EFFECT_KINDS = new Set(['automation_commit', 'automation_push', 'automation_pull_request']);
|
|
3956
3957
|
const AUTOMATION_WORKER_PAUSE_KINDS = new Set(['build', 'review', 'build_follow_up', 'automation_review_fix']);
|
|
3957
|
-
const pausedRunBelongsToProgression = (projectId, bundleId, progressionRunId, pausedRunId) => {
|
|
3958
|
-
const pausedRun = getExecutionRun(projectId, pausedRunId);
|
|
3959
|
-
const progression = getExecutionRun(projectId, progressionRunId);
|
|
3960
|
-
if (!pausedRun || !progression || progression.kind !== 'automation_progression') {
|
|
3961
|
-
return false;
|
|
3962
|
-
}
|
|
3963
|
-
const ownsBundle = listExecutionRunLinks(projectId, pausedRun.id).some(link => (link.entity_type === 'bundle'
|
|
3964
|
-
&& link.entity_id === bundleId
|
|
3965
|
-
&& (link.relationship === 'primary' || link.relationship === 'context')));
|
|
3966
|
-
if (!ownsBundle) {
|
|
3967
|
-
return false;
|
|
3968
|
-
}
|
|
3969
|
-
if (pausedRun.parent_run_id === progressionRunId) {
|
|
3970
|
-
return true;
|
|
3971
|
-
}
|
|
3972
|
-
const parent = pausedRun.parent_run_id ? getExecutionRun(projectId, pausedRun.parent_run_id) : null;
|
|
3973
|
-
return parent?.kind === 'automation_review_fix' && parent.parent_run_id === progressionRunId
|
|
3974
|
-
|| progression.parent_run_id === pausedRun.id;
|
|
3975
|
-
};
|
|
3976
3958
|
app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
3977
3959
|
const result = getRequiredProject(req);
|
|
3978
3960
|
if ('error' in result) {
|
|
@@ -3986,15 +3968,38 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
3986
3968
|
if (!bundleState || !bundleState.automation_paused_reason) {
|
|
3987
3969
|
return res.status(409).json({ error: 'Bundle automation is not paused' });
|
|
3988
3970
|
}
|
|
3989
|
-
const
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3971
|
+
const resolveCurrentDecision = () => {
|
|
3972
|
+
const currentState = getBundleAutomationState(result.project.id, bundle.id);
|
|
3973
|
+
if (!currentState?.automation_paused_reason) {
|
|
3974
|
+
return null;
|
|
3975
|
+
}
|
|
3976
|
+
return resolveAutomationResumeDecision({
|
|
3977
|
+
projectId: result.project.id,
|
|
3978
|
+
bundleId: bundle.id,
|
|
3979
|
+
state: currentState,
|
|
3980
|
+
config: resolveAutomationConfig(getBundle(bundle.id, result.project.id), getProjectById(result.project.id)),
|
|
3981
|
+
tickets: listDetailedBundleTickets(result.project.id, bundle.id),
|
|
3982
|
+
openQuestionCount: listBuildOpenQuestionsForBundle(result.project.id, bundle.id).length,
|
|
3983
|
+
questionResolutionActive: hasActiveBuildOpenQuestionBatch(result.project.id, bundle.id),
|
|
3984
|
+
});
|
|
3985
|
+
};
|
|
3986
|
+
const decision = resolveCurrentDecision();
|
|
3987
|
+
if (!decision || decision.status !== 'enabled') {
|
|
3988
|
+
const error = decision?.status === 'hidden' && decision.reason === 'question_resolution_active'
|
|
3989
|
+
? 'Build open question resolution is still in progress'
|
|
3990
|
+
: decision?.status === 'hidden' && decision.reason === 'resolve_open_questions'
|
|
3991
|
+
? 'Resolve or dismiss all Build open questions before resuming automation'
|
|
3992
|
+
: decision?.status === 'disabled' && decision.reason === 'invalid_stage_lineage'
|
|
3993
|
+
? 'The paused automation stage does not belong to the active progression'
|
|
3994
|
+
: 'Bundle automation cannot be resumed in its current state';
|
|
3995
|
+
return res.status(409).json({ error, automation_resume_decision: decision });
|
|
3996
|
+
}
|
|
3997
|
+
const revalidateDecision = () => {
|
|
3998
|
+
const current = resolveCurrentDecision();
|
|
3999
|
+
return current?.status === 'enabled'
|
|
4000
|
+
&& current.outcome === decision.outcome
|
|
4001
|
+
&& current.owner_ticket_id === decision.owner_ticket_id;
|
|
4002
|
+
};
|
|
3998
4003
|
let progressionRunId = bundleState.automation_progression_run_id;
|
|
3999
4004
|
if (!progressionRunId) {
|
|
4000
4005
|
try {
|
|
@@ -4022,12 +4027,13 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4022
4027
|
catch (error) {
|
|
4023
4028
|
return res.status(409).json({ error: error instanceof Error ? error.message : String(error) });
|
|
4024
4029
|
}
|
|
4030
|
+
if (!revalidateDecision()) {
|
|
4031
|
+
return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
|
|
4032
|
+
}
|
|
4025
4033
|
let sideEffectResume = null;
|
|
4026
|
-
let pausedRunKind = null;
|
|
4027
4034
|
if (bundleState.automation_paused_stage_run_id) {
|
|
4028
4035
|
const stageRunId = bundleState.automation_paused_stage_run_id;
|
|
4029
4036
|
const stage = getExecutionRun(result.project.id, stageRunId);
|
|
4030
|
-
pausedRunKind = stage?.kind ?? null;
|
|
4031
4037
|
if (!stage
|
|
4032
4038
|
|| (!AUTOMATION_SIDE_EFFECT_KINDS.has(stage.kind) && !AUTOMATION_WORKER_PAUSE_KINDS.has(stage.kind))
|
|
4033
4039
|
|| !pausedRunBelongsToProgression(result.project.id, bundle.id, progressionRunId, stageRunId)) {
|
|
@@ -4091,33 +4097,7 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4091
4097
|
}
|
|
4092
4098
|
}
|
|
4093
4099
|
}
|
|
4094
|
-
|
|
4095
|
-
completeAutomationProgression({
|
|
4096
|
-
projectId: result.project.id,
|
|
4097
|
-
bundleId: bundle.id,
|
|
4098
|
-
progressionRunId,
|
|
4099
|
-
domainStatus: 'manual_boundary_reached',
|
|
4100
|
-
broadcaster: io,
|
|
4101
|
-
});
|
|
4102
|
-
for (const ticket of listDetailedBundleTickets(result.project.id, bundle.id)) {
|
|
4103
|
-
io.emit('ticket:updated', ticket);
|
|
4104
|
-
}
|
|
4105
|
-
return res.json(serializeBundleDetails(result.project, bundle));
|
|
4106
|
-
}
|
|
4107
|
-
const reviewOwnerSource = bundleState.automation_paused_code === 'open_questions'
|
|
4108
|
-
? listBundleSliceTickets(result.project.id, bundle.id, 'build')
|
|
4109
|
-
.find(ticket => ticket.agent_status === 'done') ?? null
|
|
4110
|
-
: resolveBundleReviewOwner(result.project.id, bundle.id)
|
|
4111
|
-
?? listBundleSliceTickets(result.project.id, bundle.id, 'review')[0]
|
|
4112
|
-
?? (bundleState.automation_paused_code === 'review' && (pausedRunKind === 'build' || pausedRunKind === 'build_follow_up')
|
|
4113
|
-
? listBundleSliceTickets(result.project.id, bundle.id, 'build')
|
|
4114
|
-
.find(ticket => ticket.agent_status === 'done') ?? null
|
|
4115
|
-
: null)
|
|
4116
|
-
?? null;
|
|
4117
|
-
if (!reviewOwnerSource) {
|
|
4118
|
-
return res.status(409).json({ error: 'No review ticket to resume from' });
|
|
4119
|
-
}
|
|
4120
|
-
const owner = getTicket(reviewOwnerSource.id);
|
|
4100
|
+
const owner = getTicket(decision.owner_ticket_id);
|
|
4121
4101
|
if (!owner) {
|
|
4122
4102
|
return res.status(409).json({ error: 'No review ticket to resume from' });
|
|
4123
4103
|
}
|
|
@@ -4151,6 +4131,9 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4151
4131
|
};
|
|
4152
4132
|
};
|
|
4153
4133
|
if (sideEffectResume) {
|
|
4134
|
+
if (!decision.outcome.startsWith('reconcile_') || !revalidateDecision()) {
|
|
4135
|
+
return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
|
|
4136
|
+
}
|
|
4154
4137
|
try {
|
|
4155
4138
|
runAutomationProgression({
|
|
4156
4139
|
projectId: result.project.id,
|
|
@@ -4169,27 +4152,17 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4169
4152
|
}
|
|
4170
4153
|
return res.json(serializeBundleDetails(result.project, bundle));
|
|
4171
4154
|
}
|
|
4172
|
-
if (owner.state === 'review' && owner.agent_status === 'running') {
|
|
4173
|
-
return res.status(409).json({ error: 'Review already running' });
|
|
4174
|
-
}
|
|
4175
4155
|
if (owner.state === 'review' && owner.agent_status !== 'running') {
|
|
4176
|
-
const latestRun = getLatestReviewRunForContext({
|
|
4177
|
-
ticketId: owner.id,
|
|
4178
|
-
projectId: owner.project_id,
|
|
4179
|
-
worktreeBundleId: owner.worktree_bundle_id,
|
|
4180
|
-
});
|
|
4181
|
-
const findings = latestRun ? listReviewFindings(latestRun.id) : [];
|
|
4182
|
-
const blockingCount = countBlockingFindings(findings, automationConfig);
|
|
4183
4156
|
const iteration = bundleState.review_iteration_count ?? 0;
|
|
4184
|
-
if (
|
|
4185
|
-
&& automationConfig.reviewFixEnabled
|
|
4186
|
-
&& blockingCount > 0
|
|
4187
|
-
&& iteration < automationConfig.reviewMaxIterations) {
|
|
4157
|
+
if (decision.outcome === 'start_review_fix') {
|
|
4188
4158
|
let reviewFixRunId = null;
|
|
4189
4159
|
let followUpResult;
|
|
4190
4160
|
const previousIteration = bundleState.review_iteration_count ?? 0;
|
|
4191
4161
|
const previousFixLoopActive = bundleState.fix_loop_active;
|
|
4192
4162
|
try {
|
|
4163
|
+
if (!revalidateDecision()) {
|
|
4164
|
+
return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
|
|
4165
|
+
}
|
|
4193
4166
|
const progression = getAutomationProgression(result.project.id, bundle.id);
|
|
4194
4167
|
if (!progression || progression.id !== progressionRunId) {
|
|
4195
4168
|
return res.status(409).json({ error: 'Automation progression ownership is invalid' });
|
|
@@ -4219,10 +4192,11 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4219
4192
|
ticketId: owner.id,
|
|
4220
4193
|
requestedProjectId: result.project.id,
|
|
4221
4194
|
payload: {
|
|
4222
|
-
instruction:
|
|
4195
|
+
instruction: buildAutomationFixInstruction(automationConfig.reviewSeverity),
|
|
4223
4196
|
mode: 'build',
|
|
4224
4197
|
},
|
|
4225
4198
|
broadcaster: io,
|
|
4199
|
+
persistTriggerMessage: false,
|
|
4226
4200
|
initiation: {
|
|
4227
4201
|
initiator: 'automation',
|
|
4228
4202
|
causalParentRunId: reviewFix.runId,
|
|
@@ -4276,8 +4250,11 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4276
4250
|
return res.status(followUpResult.status).json({ error: followUpResult.error });
|
|
4277
4251
|
}
|
|
4278
4252
|
}
|
|
4279
|
-
else if (
|
|
4253
|
+
else if (decision.outcome === 'continue_commit_chain') {
|
|
4280
4254
|
try {
|
|
4255
|
+
if (!revalidateDecision()) {
|
|
4256
|
+
return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
|
|
4257
|
+
}
|
|
4281
4258
|
runAutomationProgression({
|
|
4282
4259
|
projectId: result.project.id,
|
|
4283
4260
|
bundleId: bundle.id,
|
|
@@ -4290,7 +4267,10 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4290
4267
|
return res.status(409).json({ error: error instanceof Error ? error.message : String(error) });
|
|
4291
4268
|
}
|
|
4292
4269
|
}
|
|
4293
|
-
else {
|
|
4270
|
+
else if (decision.outcome === 'rerun_review') {
|
|
4271
|
+
if (!revalidateDecision()) {
|
|
4272
|
+
return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
|
|
4273
|
+
}
|
|
4294
4274
|
const reviewResult = rerunTicketReviewOperation(owner, io, {
|
|
4295
4275
|
automatic: true,
|
|
4296
4276
|
initiation: { causalParentRunId: progressionRunId },
|
|
@@ -4300,8 +4280,14 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4300
4280
|
return res.status(reviewResult.status).json({ error: reviewResult.error });
|
|
4301
4281
|
}
|
|
4302
4282
|
}
|
|
4283
|
+
else {
|
|
4284
|
+
return res.status(409).json({ error: 'The selected Resume outcome no longer matches the bundle state' });
|
|
4285
|
+
}
|
|
4303
4286
|
}
|
|
4304
|
-
else if (owner.state === 'build' && owner.agent_status === 'done') {
|
|
4287
|
+
else if (owner.state === 'build' && owner.agent_status === 'done' && decision.outcome === 'start_review') {
|
|
4288
|
+
if (!revalidateDecision()) {
|
|
4289
|
+
return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
|
|
4290
|
+
}
|
|
4305
4291
|
const reviewResult = transitionBundleToReview(result.project.id, bundle.id, io, {
|
|
4306
4292
|
automatic: true,
|
|
4307
4293
|
initiation: { causalParentRunId: progressionRunId },
|