@resolveio/server-lib 22.3.145 → 22.3.146
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/package.json +1 -1
- package/util/ai-runner-manager-autopilot.d.ts +3 -0
- package/util/ai-runner-manager-autopilot.js +12 -0
- package/util/ai-runner-manager-autopilot.js.map +1 -1
- package/util/ai-runner-manager-policy.d.ts +113 -0
- package/util/ai-runner-manager-policy.js +771 -36
- package/util/ai-runner-manager-policy.js.map +1 -1
|
@@ -47,6 +47,8 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
47
47
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
48
48
|
};
|
|
49
49
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.buildResolveIOAIManagerHotfixFirstReleasePolicy = buildResolveIOAIManagerHotfixFirstReleasePolicy;
|
|
51
|
+
exports.isResolveIOAIManagerSafeAutoDispatch = isResolveIOAIManagerSafeAutoDispatch;
|
|
50
52
|
exports.normalizeResolveIOAIManagerFailureClass = normalizeResolveIOAIManagerFailureClass;
|
|
51
53
|
exports.fingerprintResolveIOAIManagerBlocker = fingerprintResolveIOAIManagerBlocker;
|
|
52
54
|
exports.hashResolveIOAIManagerEvidence = hashResolveIOAIManagerEvidence;
|
|
@@ -56,9 +58,11 @@ exports.buildResolveIOAIManagerRecoveryActionPacket = buildResolveIOAIManagerRec
|
|
|
56
58
|
exports.decideResolveIOAIManagerRecoveryActionDispatch = decideResolveIOAIManagerRecoveryActionDispatch;
|
|
57
59
|
exports.appendResolveIOAIManagerRecoveryActionDispatch = appendResolveIOAIManagerRecoveryActionDispatch;
|
|
58
60
|
exports.buildResolveIOAIManagerRecoveryExecutionDirective = buildResolveIOAIManagerRecoveryExecutionDirective;
|
|
61
|
+
exports.assessResolveIOAIManagerEvidenceChange = assessResolveIOAIManagerEvidenceChange;
|
|
59
62
|
exports.decideResolveIOAIManagerRecoveryGate = decideResolveIOAIManagerRecoveryGate;
|
|
60
63
|
exports.buildResolveIOAIManagerRecoveryPlan = buildResolveIOAIManagerRecoveryPlan;
|
|
61
64
|
exports.decideResolveIOAIManagerPolicy = decideResolveIOAIManagerPolicy;
|
|
65
|
+
exports.buildResolveIOAIManagerRecoveryReplayMatrix = buildResolveIOAIManagerRecoveryReplayMatrix;
|
|
62
66
|
function cleanText(value, max) {
|
|
63
67
|
if (max === void 0) { max = 2000; }
|
|
64
68
|
return String(value || '').replace(/\s+/g, ' ').trim().slice(0, max);
|
|
@@ -92,6 +96,292 @@ function cleanList(values, limit, max) {
|
|
|
92
96
|
}
|
|
93
97
|
return result;
|
|
94
98
|
}
|
|
99
|
+
function releaseStatusIsBlocked(value) {
|
|
100
|
+
return /fail|error|blocked|missing|empty|not ready|not_ready|denied|invalid|timeout|stale/i.test(value);
|
|
101
|
+
}
|
|
102
|
+
function releaseStatusIsTerminalDeploy(value) {
|
|
103
|
+
return /requested|queued|in.?progress|completed|complete|success|succeeded|pass|passed|published|deployed|failed|error|blocked/i.test(value);
|
|
104
|
+
}
|
|
105
|
+
function buildReleaseAllowedActions(action) {
|
|
106
|
+
if (action === 'wait_for_active_deploy') {
|
|
107
|
+
return ['wait_for_current_deploy_result', 'collect_current_deploy_log', 'refresh_release_snapshot'];
|
|
108
|
+
}
|
|
109
|
+
if (action === 'block_duplicate_deploy') {
|
|
110
|
+
return ['collect_existing_deploy_evidence', 'hotfix_release_artifact', 'request_force_deploy_with_reason'];
|
|
111
|
+
}
|
|
112
|
+
if (action === 'review_force_deploy') {
|
|
113
|
+
return ['verify_force_deploy_reason', 'rerun_failed_release_gate_once', 'record_force_deploy_evidence'];
|
|
114
|
+
}
|
|
115
|
+
if (action === 'deploy_new_artifact_after_release_gate') {
|
|
116
|
+
return ['verify_new_artifact_fingerprint', 'run_release_gate_once', 'record_publish_deploy_evidence'];
|
|
117
|
+
}
|
|
118
|
+
if (action === 'build_artifact_first') {
|
|
119
|
+
return ['build_missing_release_artifact', 'record_artifact_fingerprint', 'run_release_gate_once'];
|
|
120
|
+
}
|
|
121
|
+
return ['hotfix_live_runner_or_release_artifact', 'rerun_failed_release_gate_only', 'record_release_evidence'];
|
|
122
|
+
}
|
|
123
|
+
function hotfixStep(id, label, channel, options) {
|
|
124
|
+
if (options === void 0) { options = {}; }
|
|
125
|
+
return {
|
|
126
|
+
id: id,
|
|
127
|
+
label: label,
|
|
128
|
+
channel: channel,
|
|
129
|
+
safeToAutoRun: options.safeToAutoRun === true,
|
|
130
|
+
requiresFullDeploy: options.requiresFullDeploy === true,
|
|
131
|
+
requiredEvidence: options.requiredEvidence || [],
|
|
132
|
+
successEvidence: options.successEvidence || [],
|
|
133
|
+
blockedBy: options.blockedBy || []
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function buildHotfixFirstReleasePlan(input) {
|
|
137
|
+
var surface = cleanText(input.surface || 'runner', 80)
|
|
138
|
+
.toLowerCase()
|
|
139
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
140
|
+
.replace(/^_+|_+$/g, '') || 'runner';
|
|
141
|
+
var commonAcceptance = [
|
|
142
|
+
'failed release gate is rerun once and passes',
|
|
143
|
+
'artifact fingerprint or hotfix evidence is recorded',
|
|
144
|
+
'operator console shows no active duplicate deploy blocker'
|
|
145
|
+
];
|
|
146
|
+
if (input.action === 'wait_for_active_deploy') {
|
|
147
|
+
return {
|
|
148
|
+
planId: "".concat(surface, ":wait_for_active_deploy"),
|
|
149
|
+
label: 'Wait For Active Deploy',
|
|
150
|
+
recommendedChannel: 'release_artifact',
|
|
151
|
+
reason: input.reason,
|
|
152
|
+
fullDeployAvoided: true,
|
|
153
|
+
steps: [
|
|
154
|
+
hotfixStep('collect_active_deploy_log', 'Collect active deploy log', 'release_artifact', {
|
|
155
|
+
safeToAutoRun: true,
|
|
156
|
+
requiredEvidence: ['active deploy id or release operation id'],
|
|
157
|
+
successEvidence: ['terminal deploy status and release log captured']
|
|
158
|
+
})
|
|
159
|
+
],
|
|
160
|
+
acceptanceEvidence: commonAcceptance,
|
|
161
|
+
escalationTriggers: ['active deploy exceeds timeout', 'active deploy fails without a release log']
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
if (input.action === 'deploy_new_artifact_after_release_gate') {
|
|
165
|
+
return {
|
|
166
|
+
planId: "".concat(surface, ":deploy_new_artifact_after_release_gate"),
|
|
167
|
+
label: 'Deploy New Artifact After Release Gate',
|
|
168
|
+
recommendedChannel: 'new_artifact_deploy',
|
|
169
|
+
reason: input.reason,
|
|
170
|
+
fullDeployAvoided: false,
|
|
171
|
+
steps: [
|
|
172
|
+
hotfixStep('verify_new_artifact_fingerprint', 'Verify new artifact fingerprint', 'new_artifact_deploy', {
|
|
173
|
+
safeToAutoRun: true,
|
|
174
|
+
requiresFullDeploy: true,
|
|
175
|
+
requiredEvidence: ['current artifact fingerprint differs from last deployed fingerprint'],
|
|
176
|
+
successEvidence: ['release gate permits one full deploy']
|
|
177
|
+
})
|
|
178
|
+
],
|
|
179
|
+
acceptanceEvidence: [
|
|
180
|
+
'new artifact fingerprint recorded',
|
|
181
|
+
'release gate passed before full deploy',
|
|
182
|
+
'deploy/publish result recorded'
|
|
183
|
+
],
|
|
184
|
+
escalationTriggers: ['artifact fingerprint matches last deploy', 'release gate fails']
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (input.action === 'build_artifact_first') {
|
|
188
|
+
return {
|
|
189
|
+
planId: "".concat(surface, ":build_artifact_first"),
|
|
190
|
+
label: 'Build Artifact First',
|
|
191
|
+
recommendedChannel: 'artifact_build',
|
|
192
|
+
reason: input.reason,
|
|
193
|
+
fullDeployAvoided: true,
|
|
194
|
+
steps: [
|
|
195
|
+
hotfixStep('build_once_record_fingerprint', 'Build once and record fingerprint', 'artifact_build', {
|
|
196
|
+
safeToAutoRun: false,
|
|
197
|
+
requiredEvidence: ['missing artifact fingerprint', 'release gate reason for building'],
|
|
198
|
+
successEvidence: ['artifact fingerprint recorded before any deploy']
|
|
199
|
+
})
|
|
200
|
+
],
|
|
201
|
+
acceptanceEvidence: ['artifact fingerprint exists', 'no deploy queued before release gate'],
|
|
202
|
+
escalationTriggers: ['build repeats without a new fingerprint', 'build failure lacks compile log']
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
if (input.action === 'review_force_deploy') {
|
|
206
|
+
return {
|
|
207
|
+
planId: "".concat(surface, ":review_force_deploy"),
|
|
208
|
+
label: 'Review Force Deploy',
|
|
209
|
+
recommendedChannel: 'force_deploy_review',
|
|
210
|
+
reason: input.reason,
|
|
211
|
+
fullDeployAvoided: false,
|
|
212
|
+
steps: [
|
|
213
|
+
hotfixStep('verify_force_deploy_reason', 'Verify force deploy reason', 'force_deploy_review', {
|
|
214
|
+
requiredEvidence: ['explicit force_deploy reason', 'why hotfix cannot resolve the release blocker'],
|
|
215
|
+
successEvidence: ['one allowed deploy attempt is recorded with reason']
|
|
216
|
+
})
|
|
217
|
+
],
|
|
218
|
+
acceptanceEvidence: ['force deploy evidence recorded', 'duplicate fingerprint exception is auditable'],
|
|
219
|
+
escalationTriggers: ['force deploy reason is empty', 'same force deploy fails twice']
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
planId: "".concat(surface, ":").concat(input.action),
|
|
224
|
+
label: input.action === 'block_duplicate_deploy' ? 'Hotfix Or Force Deploy' : 'Hotfix Release Artifact',
|
|
225
|
+
recommendedChannel: input.releaseBlocked ? 'release_artifact' : 'static_ui',
|
|
226
|
+
reason: input.reason,
|
|
227
|
+
fullDeployAvoided: true,
|
|
228
|
+
steps: [
|
|
229
|
+
hotfixStep('static_ui_hotfix', 'Static UI hotfix', 'static_ui', {
|
|
230
|
+
safeToAutoRun: true,
|
|
231
|
+
requiredEvidence: ['built dist path', 'target S3 bucket and CloudFront distribution', 'changed frontend bundle or asset list'],
|
|
232
|
+
successEvidence: ['S3 upload result', 'CloudFront invalidation id', 'public bundle contains expected hotfix marker']
|
|
233
|
+
}),
|
|
234
|
+
hotfixStep('backend_js_hotfix', 'Backend JS hotfix', 'backend_js', {
|
|
235
|
+
requiredEvidence: ['compiled JS artifact path', 'target backend host', 'diff limited to runner/operator code'],
|
|
236
|
+
successEvidence: ['remote file checksum', 'service restart or process reload evidence', 'self-test passes']
|
|
237
|
+
}),
|
|
238
|
+
hotfixStep('config_seed_cache_restart', 'Config, seed, cache, or restart repair', 'config', {
|
|
239
|
+
safeToAutoRun: true,
|
|
240
|
+
requiredEvidence: ['exact config/seed/cache key or process name', 'why no product artifact changed'],
|
|
241
|
+
successEvidence: ['release gate rerun result', 'operator console release snapshot refreshed']
|
|
242
|
+
})
|
|
243
|
+
],
|
|
244
|
+
acceptanceEvidence: commonAcceptance,
|
|
245
|
+
escalationTriggers: [
|
|
246
|
+
'hotfix changes customer-facing product code outside the release artifact',
|
|
247
|
+
'same release gate fails twice after hotfix evidence',
|
|
248
|
+
'force deploy is requested without a reason'
|
|
249
|
+
]
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function buildResolveIOAIManagerHotfixFirstReleasePolicy(input) {
|
|
253
|
+
if (input === void 0) { input = {}; }
|
|
254
|
+
var surface = cleanText(input.surface || 'runner', 120);
|
|
255
|
+
var deployStatus = cleanText(input.deployStatus, 160);
|
|
256
|
+
var publishStatus = cleanText(input.publishStatus, 160);
|
|
257
|
+
var sampleDataStatus = cleanText(input.sampleDataStatus, 160);
|
|
258
|
+
var deployFingerprint = cleanText(input.deployFingerprint, 240);
|
|
259
|
+
var lastDeployFingerprint = cleanText(input.lastDeployFingerprint, 240);
|
|
260
|
+
var fingerprintMatchesLast = !!deployFingerprint && !!lastDeployFingerprint && deployFingerprint === lastDeployFingerprint;
|
|
261
|
+
var releaseBlocked = [deployStatus, publishStatus, sampleDataStatus].some(releaseStatusIsBlocked);
|
|
262
|
+
var duplicateDeployBlocked = fingerprintMatchesLast
|
|
263
|
+
&& input.forceDeploy !== true
|
|
264
|
+
&& releaseStatusIsTerminalDeploy([deployStatus, publishStatus].filter(Boolean).join(' '));
|
|
265
|
+
var recommendedAction = 'hotfix_release_artifact';
|
|
266
|
+
var label = 'Hotfix Release Artifact';
|
|
267
|
+
var reason = 'Repair the live runner/operator code, release config, domain, seed-data, or release artifact and rerun only the failed release gate.';
|
|
268
|
+
var fullDeployAllowed = false;
|
|
269
|
+
if (input.activeDeploy === true) {
|
|
270
|
+
recommendedAction = 'wait_for_active_deploy';
|
|
271
|
+
label = 'Wait For Active Deploy';
|
|
272
|
+
reason = 'A deploy is already queued or running; collect that result before spending another deploy cycle.';
|
|
273
|
+
}
|
|
274
|
+
else if (duplicateDeployBlocked) {
|
|
275
|
+
recommendedAction = 'block_duplicate_deploy';
|
|
276
|
+
label = 'Block Duplicate Deploy';
|
|
277
|
+
reason = 'The same artifact fingerprint already has release status; hotfix or provide explicit force_deploy evidence before rerunning it.';
|
|
278
|
+
}
|
|
279
|
+
else if (fingerprintMatchesLast && input.forceDeploy === true) {
|
|
280
|
+
recommendedAction = 'review_force_deploy';
|
|
281
|
+
label = 'Review Force Deploy';
|
|
282
|
+
reason = 'force_deploy was explicitly requested for a repeated artifact; require a reason and rerun only the failed release gate.';
|
|
283
|
+
fullDeployAllowed = true;
|
|
284
|
+
}
|
|
285
|
+
else if (input.hasNewArtifact === false && !releaseBlocked) {
|
|
286
|
+
recommendedAction = 'build_artifact_first';
|
|
287
|
+
label = 'Build Artifact First';
|
|
288
|
+
reason = 'No release artifact fingerprint is available yet; build once, record the fingerprint, and avoid repeated deploys.';
|
|
289
|
+
}
|
|
290
|
+
else if (input.hasNewArtifact === true && !releaseBlocked) {
|
|
291
|
+
recommendedAction = 'deploy_new_artifact_after_release_gate';
|
|
292
|
+
label = 'Deploy New Artifact After Release Gate';
|
|
293
|
+
reason = 'A new artifact can be deployed after the release gate proves the artifact is new and ready.';
|
|
294
|
+
fullDeployAllowed = true;
|
|
295
|
+
}
|
|
296
|
+
var allowedActions = buildReleaseAllowedActions(recommendedAction);
|
|
297
|
+
var hotfixPlan = buildHotfixFirstReleasePlan({
|
|
298
|
+
action: recommendedAction,
|
|
299
|
+
surface: surface,
|
|
300
|
+
reason: reason,
|
|
301
|
+
releaseBlocked: releaseBlocked
|
|
302
|
+
});
|
|
303
|
+
return {
|
|
304
|
+
policy: 'hotfix_first',
|
|
305
|
+
surface: surface,
|
|
306
|
+
recommendedAction: recommendedAction,
|
|
307
|
+
label: label,
|
|
308
|
+
reason: reason,
|
|
309
|
+
hotfixPreferred: recommendedAction !== 'deploy_new_artifact_after_release_gate' && recommendedAction !== 'review_force_deploy',
|
|
310
|
+
fullDeployAllowed: fullDeployAllowed,
|
|
311
|
+
duplicateDeployBlocked: duplicateDeployBlocked,
|
|
312
|
+
forceDeployRequiredToRepeat: true,
|
|
313
|
+
statuses: {
|
|
314
|
+
deploy: deployStatus,
|
|
315
|
+
publish: publishStatus,
|
|
316
|
+
sampleData: sampleDataStatus
|
|
317
|
+
},
|
|
318
|
+
fingerprints: {
|
|
319
|
+
current: deployFingerprint,
|
|
320
|
+
last: lastDeployFingerprint,
|
|
321
|
+
matchesLast: fingerprintMatchesLast
|
|
322
|
+
},
|
|
323
|
+
hotfixPlan: hotfixPlan,
|
|
324
|
+
allowedActions: allowedActions,
|
|
325
|
+
forbiddenActions: [
|
|
326
|
+
'rerun full builder loop for a release-only blocker',
|
|
327
|
+
'queue duplicate deploy without force_deploy evidence',
|
|
328
|
+
'publish/deploy again before reading the failed release log',
|
|
329
|
+
'change core workflow after business proof passed unless release evidence proves it is required'
|
|
330
|
+
],
|
|
331
|
+
requiredEvidence: [
|
|
332
|
+
'failed release gate log or active deploy result',
|
|
333
|
+
'deploy artifact fingerprint comparison',
|
|
334
|
+
'hotfix/config/seed/domain change evidence when no new product artifact is needed',
|
|
335
|
+
'force_deploy reason when repeating the same fingerprint'
|
|
336
|
+
]
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
function isResolveIOAIManagerSafeAutoDispatch(input) {
|
|
340
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
341
|
+
var normalizedInput = typeof input === 'string'
|
|
342
|
+
? { dispatchAction: input }
|
|
343
|
+
: (input || {});
|
|
344
|
+
var dispatchAction = cleanText(normalizedInput.dispatchAction || ((_a = normalizedInput.directive) === null || _a === void 0 ? void 0 : _a.dispatchAction), 120);
|
|
345
|
+
var directiveAllowed = (_b = normalizedInput.directive) === null || _b === void 0 ? void 0 : _b.allowed;
|
|
346
|
+
var actionAutoRunnable = (_c = normalizedInput.action) === null || _c === void 0 ? void 0 : _c.autoRunnable;
|
|
347
|
+
var productRepairAllowed = ((_d = normalizedInput.directive) === null || _d === void 0 ? void 0 : _d.canRunProductRepair) === true
|
|
348
|
+
|| ((_e = normalizedInput.directive) === null || _e === void 0 ? void 0 : _e.productRepairAllowed) === true
|
|
349
|
+
|| ((_f = normalizedInput.action) === null || _f === void 0 ? void 0 : _f.productRepairAllowed) === true;
|
|
350
|
+
var expensiveModelAllowed = ((_g = normalizedInput.directive) === null || _g === void 0 ? void 0 : _g.canRunExpensiveModel) === true
|
|
351
|
+
|| ((_h = normalizedInput.directive) === null || _h === void 0 ? void 0 : _h.expensiveModelAllowed) === true
|
|
352
|
+
|| ((_j = normalizedInput.action) === null || _j === void 0 ? void 0 : _j.expensiveModelAllowed) === true;
|
|
353
|
+
if (!dispatchAction || dispatchAction === 'park_manual') {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
if (directiveAllowed === false || actionAutoRunnable === false) {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
if ([
|
|
360
|
+
'run_evidence_probe',
|
|
361
|
+
'run_read_only_diagnosis',
|
|
362
|
+
'run_infra_repair',
|
|
363
|
+
'run_compile_repair'
|
|
364
|
+
].includes(dispatchAction)) {
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
if (dispatchAction === 'run_release_repair') {
|
|
368
|
+
return normalizedInput.includeReleaseRepair !== false;
|
|
369
|
+
}
|
|
370
|
+
if (dispatchAction === 'run_journey_contract_repair') {
|
|
371
|
+
return normalizedInput.includeJourneyContractRepair !== false && productRepairAllowed !== true;
|
|
372
|
+
}
|
|
373
|
+
if (dispatchAction === 'run_business_assertion_repair') {
|
|
374
|
+
return normalizedInput.includeBusinessProofRepair === true
|
|
375
|
+
&& productRepairAllowed !== true
|
|
376
|
+
&& expensiveModelAllowed !== true;
|
|
377
|
+
}
|
|
378
|
+
if (dispatchAction === 'run_targeted_product_repair') {
|
|
379
|
+
return normalizedInput.includeProductRepair === true
|
|
380
|
+
&& productRepairAllowed === true
|
|
381
|
+
&& expensiveModelAllowed !== true;
|
|
382
|
+
}
|
|
383
|
+
return dispatchAction === 'advance' || dispatchAction === 'continue_gate';
|
|
384
|
+
}
|
|
95
385
|
function isoNow(value) {
|
|
96
386
|
if (value instanceof Date) {
|
|
97
387
|
return value.toISOString();
|
|
@@ -399,13 +689,23 @@ function buildResolveIOAIManagerRecoveryActionPacket(input) {
|
|
|
399
689
|
|| checkpoint.status === 'parked'
|
|
400
690
|
|| checkpoint.attempts >= checkpoint.maxAttemptsBeforePark;
|
|
401
691
|
var stopWhen = Array.from(new Set(__spreadArray(__spreadArray([], __read(probe.stopConditions), false), __read((requireNewEvidence ? ['same blocker fingerprint and same evidence hash after probe'] : [])), false).map(function (entry) { return cleanText(entry, 500); }).filter(Boolean))).slice(0, 30);
|
|
402
|
-
var resetLoopWhen = Array.from(new Set(__spreadArray(__spreadArray(__spreadArray([], __read(checkpoint.loopResetEvidence), false), __read(probe.loopResetEvidence), false), __read((requireNewEvidence ? [
|
|
692
|
+
var resetLoopWhen = Array.from(new Set(__spreadArray(__spreadArray(__spreadArray([], __read(checkpoint.loopResetEvidence), false), __read(probe.loopResetEvidence), false), __read((requireNewEvidence ? [
|
|
693
|
+
'new material evidence: changed blocker, validated diagnosis/journey, business proof, compile/infra/release proof, or new actionable trace',
|
|
694
|
+
'weak hash-only evidence does not reset the loop'
|
|
695
|
+
] : [])), false).map(function (entry) { return cleanText(entry, 500); }).filter(Boolean))).slice(0, 30);
|
|
403
696
|
var nextCommands = probe.steps
|
|
404
697
|
.map(function (step) { return cleanText(step.commandHint || "".concat(step.kind, ":").concat(step.id), 500); })
|
|
405
698
|
.filter(Boolean)
|
|
406
699
|
.slice(0, 12);
|
|
700
|
+
var releasePolicy = mode === 'repair_release'
|
|
701
|
+
? buildResolveIOAIManagerHotfixFirstReleasePolicy({
|
|
702
|
+
surface: 'manager_recovery',
|
|
703
|
+
deployStatus: checkpoint.stepType,
|
|
704
|
+
publishStatus: checkpoint.lane
|
|
705
|
+
})
|
|
706
|
+
: undefined;
|
|
407
707
|
var now = isoNow(input.now);
|
|
408
|
-
return __assign(__assign({ actionId: stableHash('mgr-action', {
|
|
708
|
+
return __assign(__assign(__assign({ actionId: stableHash('mgr-action', {
|
|
409
709
|
checkpointId: checkpoint.checkpointId,
|
|
410
710
|
probeId: probe.probeId,
|
|
411
711
|
mode: mode,
|
|
@@ -413,12 +713,16 @@ function buildResolveIOAIManagerRecoveryActionPacket(input) {
|
|
|
413
713
|
blockerFingerprint: checkpoint.blockerFingerprint
|
|
414
714
|
}), checkpointId: checkpoint.checkpointId, probeId: probe.probeId, recoveryClass: checkpoint.recoveryClass, mode: mode, label: recoveryActionLabelFor(mode, checkpoint), lane: checkpoint.lane, stepType: checkpoint.stepType, primaryStepKind: (primaryStep === null || primaryStep === void 0 ? void 0 : primaryStep.kind) || 'none', objective: mode === 'collect_evidence'
|
|
415
715
|
? probe.objective
|
|
416
|
-
: cleanText(checkpoint.objective || probe.objective, 1000), evidenceOnly: evidenceOnly, autoRunnable: recoveryActionAutoRunnable(mode, probe), productRepairAllowed: checkpoint.productRepairAllowed && !evidenceOnly && checkpoint.status !== 'parked', expensiveModelAllowed: checkpoint.expensiveModelAllowed && checkpoint.status !== 'parked', canResetLoopAfterEvidence: resetLoopWhen.length > 0, maxAttemptsBeforePark: checkpoint.maxAttemptsBeforePark, requiredArtifacts: probe.requiredArtifacts.slice(0, 20), nextCommands:
|
|
716
|
+
: cleanText(checkpoint.objective || probe.objective, 1000), evidenceOnly: evidenceOnly, autoRunnable: recoveryActionAutoRunnable(mode, probe), productRepairAllowed: checkpoint.productRepairAllowed && !evidenceOnly && checkpoint.status !== 'parked', expensiveModelAllowed: checkpoint.expensiveModelAllowed && checkpoint.status !== 'parked', canResetLoopAfterEvidence: resetLoopWhen.length > 0, maxAttemptsBeforePark: checkpoint.maxAttemptsBeforePark, requiredArtifacts: probe.requiredArtifacts.slice(0, 20), nextCommands: releasePolicy
|
|
717
|
+
? Array.from(new Set(__spreadArray(__spreadArray([], __read(nextCommands), false), __read(releasePolicy.allowedActions), false))).slice(0, 12)
|
|
718
|
+
: nextCommands, successCriteria: releasePolicy
|
|
719
|
+
? Array.from(new Set(__spreadArray(__spreadArray([], __read(probe.acceptanceEvidence), false), __read(releasePolicy.requiredEvidence), false))).slice(0, 20)
|
|
720
|
+
: probe.acceptanceEvidence.slice(0, 20), retryPolicy: {
|
|
417
721
|
allowImmediateRetry: checkpoint.status !== 'parked' && mode !== 'manual_review',
|
|
418
722
|
requireNewEvidence: requireNewEvidence,
|
|
419
723
|
resetLoopWhen: resetLoopWhen,
|
|
420
724
|
stopWhen: stopWhen
|
|
421
|
-
} }, (mode === 'collect_evidence' ? { blockedReason: 'Manager parked this loop until the recovery action records new evidence.' } : {})), { createdAt: now });
|
|
725
|
+
} }, (releasePolicy ? { releasePolicy: releasePolicy } : {})), (mode === 'collect_evidence' ? { blockedReason: 'Manager parked this loop until the recovery action records new evidence.' } : {})), { createdAt: now });
|
|
422
726
|
}
|
|
423
727
|
function dispatchActionForMode(mode) {
|
|
424
728
|
var map = {
|
|
@@ -592,7 +896,7 @@ function recoveryDirectiveReason(action, decision, current) {
|
|
|
592
896
|
].filter(Boolean).join(' | ');
|
|
593
897
|
}
|
|
594
898
|
function buildResolveIOAIManagerRecoveryExecutionDirective(input) {
|
|
595
|
-
var _a, _b, _c, _d;
|
|
899
|
+
var _a, _b, _c, _d, _e;
|
|
596
900
|
var action = input.action;
|
|
597
901
|
var dispatchDecision = input.dispatchDecision || decideResolveIOAIManagerRecoveryActionDispatch({
|
|
598
902
|
action: action,
|
|
@@ -606,7 +910,7 @@ function buildResolveIOAIManagerRecoveryExecutionDirective(input) {
|
|
|
606
910
|
var stepType = cleanText((action === null || action === void 0 ? void 0 : action.stepType) || ((_b = input.current) === null || _b === void 0 ? void 0 : _b.stepType) || '', 120);
|
|
607
911
|
var rerunReason = recoveryDirectiveReason(action, dispatchDecision, input.current);
|
|
608
912
|
var surface = cleanText(input.surface || 'runner', 120);
|
|
609
|
-
return __assign(__assign({ directiveId: stableHash('mgr-directive', {
|
|
913
|
+
return __assign(__assign(__assign({ directiveId: stableHash('mgr-directive', {
|
|
610
914
|
surface: surface,
|
|
611
915
|
actionId: (action === null || action === void 0 ? void 0 : action.actionId) || '',
|
|
612
916
|
dispatchAction: dispatchAction,
|
|
@@ -614,14 +918,100 @@ function buildResolveIOAIManagerRecoveryExecutionDirective(input) {
|
|
|
614
918
|
evidenceHash: ((_c = dispatchDecision.dispatchRecord) === null || _c === void 0 ? void 0 : _c.evidenceHash) || ((_d = input.current) === null || _d === void 0 ? void 0 : _d.evidenceHash) || ''
|
|
615
919
|
}), surface: surface, dispatchAction: dispatchAction, phase: phase, allowed: dispatchDecision.allowed, status: dispatchDecision.status, reason: dispatchDecision.reason, lane: lane, stepType: stepType, nextActionLabel: cleanText(action === null || action === void 0 ? void 0 : action.label, 160) || dispatchAction, rerunReason: rerunReason, evidenceOnly: (action === null || action === void 0 ? void 0 : action.evidenceOnly) !== false || dispatchAction === 'run_evidence_probe', autoRunnable: (action === null || action === void 0 ? void 0 : action.autoRunnable) === true, productRepairAllowed: (action === null || action === void 0 ? void 0 : action.productRepairAllowed) === true, expensiveModelAllowed: (action === null || action === void 0 ? void 0 : action.expensiveModelAllowed) === true, canRunProductRepair: dispatchDecision.canRunProductRepair, canRunExpensiveModel: dispatchDecision.canRunExpensiveModel, canResetLoopAfterEvidence: (action === null || action === void 0 ? void 0 : action.canResetLoopAfterEvidence) === true, requiresNewEvidence: dispatchDecision.requiresNewEvidence, newEvidence: dispatchDecision.newEvidence, maxAttemptsBeforePark: Math.max(1, Number((action === null || action === void 0 ? void 0 : action.maxAttemptsBeforePark) || 1) || 1), requiredArtifacts: cleanList(action === null || action === void 0 ? void 0 : action.requiredArtifacts, 20, 500), nextCommands: cleanList(action === null || action === void 0 ? void 0 : action.nextCommands, 20, 500), successCriteria: cleanList(action === null || action === void 0 ? void 0 : action.successCriteria, 20, 500), forbiddenActions: (action === null || action === void 0 ? void 0 : action.productRepairAllowed) === true
|
|
616
920
|
? []
|
|
617
|
-
:
|
|
921
|
+
: Array.from(new Set(__spreadArray([
|
|
922
|
+
'Do not run product-code repair from this directive unless canRunProductRepair is true.'
|
|
923
|
+
], __read((((_e = action === null || action === void 0 ? void 0 : action.releasePolicy) === null || _e === void 0 ? void 0 : _e.forbiddenActions) || [])), false))).slice(0, 20) }, (dispatchDecision.dispatchRecord ? { dispatchRecord: dispatchDecision.dispatchRecord } : {})), ((action === null || action === void 0 ? void 0 : action.releasePolicy) ? { releasePolicy: action.releasePolicy } : {})), { createdAt: now });
|
|
618
924
|
}
|
|
619
|
-
function
|
|
925
|
+
function newListEntries(current, previous) {
|
|
620
926
|
var existing = new Set(previous.map(function (entry) { return cleanText(entry, 500); }).filter(Boolean));
|
|
621
|
-
return current
|
|
622
|
-
|
|
623
|
-
return
|
|
624
|
-
|
|
927
|
+
return current
|
|
928
|
+
.map(function (entry) { return cleanText(entry, 500); })
|
|
929
|
+
.filter(function (entry) { return entry && !existing.has(entry); });
|
|
930
|
+
}
|
|
931
|
+
function recordLane(value) {
|
|
932
|
+
return cleanText(value === null || value === void 0 ? void 0 : value.lane, 80);
|
|
933
|
+
}
|
|
934
|
+
function recordStepType(value) {
|
|
935
|
+
return cleanText(value === null || value === void 0 ? void 0 : value.stepType, 80);
|
|
936
|
+
}
|
|
937
|
+
function recordFailureClass(value) {
|
|
938
|
+
var valueText = cleanText(value === null || value === void 0 ? void 0 : value.failureClass, 80);
|
|
939
|
+
return valueText ? normalizeResolveIOAIManagerFailureClass(valueText) : '';
|
|
940
|
+
}
|
|
941
|
+
function materialEvidenceText(record, paths) {
|
|
942
|
+
if (paths === void 0) { paths = []; }
|
|
943
|
+
return __spreadArray([
|
|
944
|
+
cleanText(record === null || record === void 0 ? void 0 : record.blocker, 1200),
|
|
945
|
+
cleanText(record === null || record === void 0 ? void 0 : record.summary, 1200)
|
|
946
|
+
], __read(paths.map(function (path) { return cleanText(path, 500); })), false).filter(Boolean).join(' ').toLowerCase();
|
|
947
|
+
}
|
|
948
|
+
function hasMaterialEvidenceLanguage(text) {
|
|
949
|
+
return /(business|assertion|proof|before|after|dom|trace|stack|network|mongo|query|diff|scope|diagnosis|journey|contract|workflow|compile|build|preflight|infra|chrome|puppeteer|release|publish|deploy|sample|seed|route|auth|hydration|performance|slow|owner|root.?cause|repro|pdf|export|upload|import|filter|invoice|saved|calculated|comparison|report)/i.test(text);
|
|
950
|
+
}
|
|
951
|
+
function assessResolveIOAIManagerEvidenceChange(previous, current, fallbackObjective) {
|
|
952
|
+
var currentRecord = current || {};
|
|
953
|
+
var previousRecord = previous;
|
|
954
|
+
var previousEvidenceHash = previousRecord ? cleanText(previousRecord.evidenceHash, 160) || hashResolveIOAIManagerEvidence(previousRecord) : '';
|
|
955
|
+
var currentEvidenceHash = hashResolveIOAIManagerEvidence(currentRecord);
|
|
956
|
+
var previousBlockerFingerprint = previousRecord
|
|
957
|
+
? cleanText(previousRecord.blockerFingerprint, 160) || resolveResolveIOAIManagerBlockerFingerprint(previousRecord, fallbackObjective)
|
|
958
|
+
: '';
|
|
959
|
+
var currentBlockerFingerprint = resolveResolveIOAIManagerBlockerFingerprint(currentRecord, fallbackObjective);
|
|
960
|
+
var previousChangedFiles = cleanList(previousRecord === null || previousRecord === void 0 ? void 0 : previousRecord.changedFiles, 80, 500);
|
|
961
|
+
var currentChangedFiles = cleanList(currentRecord.changedFiles, 80, 500);
|
|
962
|
+
var previousArtifactPaths = cleanList(previousRecord === null || previousRecord === void 0 ? void 0 : previousRecord.artifactPaths, 80, 500);
|
|
963
|
+
var currentArtifactPaths = cleanList(currentRecord.artifactPaths, 80, 500);
|
|
964
|
+
var addedChangedFiles = newListEntries(currentChangedFiles, previousChangedFiles);
|
|
965
|
+
var addedArtifactPaths = newListEntries(currentArtifactPaths, previousArtifactPaths);
|
|
966
|
+
var signals = [];
|
|
967
|
+
if (previousEvidenceHash && currentEvidenceHash !== previousEvidenceHash) {
|
|
968
|
+
signals.push('evidence_hash_changed');
|
|
969
|
+
}
|
|
970
|
+
if (previousBlockerFingerprint && currentBlockerFingerprint !== previousBlockerFingerprint) {
|
|
971
|
+
signals.push('blocker_fingerprint_changed');
|
|
972
|
+
}
|
|
973
|
+
if (recordLane(previousRecord) && recordLane(previousRecord) !== recordLane(currentRecord)) {
|
|
974
|
+
signals.push('lane_changed');
|
|
975
|
+
}
|
|
976
|
+
if (recordStepType(previousRecord) && recordStepType(previousRecord) !== recordStepType(currentRecord)) {
|
|
977
|
+
signals.push('step_type_changed');
|
|
978
|
+
}
|
|
979
|
+
if (recordFailureClass(previousRecord) && recordFailureClass(previousRecord) !== recordFailureClass(currentRecord)) {
|
|
980
|
+
signals.push('failure_class_changed');
|
|
981
|
+
}
|
|
982
|
+
if (addedChangedFiles.length) {
|
|
983
|
+
signals.push('changed_files_added');
|
|
984
|
+
}
|
|
985
|
+
if (addedArtifactPaths.length) {
|
|
986
|
+
signals.push('artifact_paths_added');
|
|
987
|
+
}
|
|
988
|
+
if (isPassingOutcome(currentRecord)) {
|
|
989
|
+
signals.push('passing_outcome');
|
|
990
|
+
}
|
|
991
|
+
var changed = signals.length > 0;
|
|
992
|
+
var evidenceText = materialEvidenceText(currentRecord, addedArtifactPaths);
|
|
993
|
+
var pathOrSummaryHasMaterialSignal = hasMaterialEvidenceLanguage(evidenceText);
|
|
994
|
+
var proof = signals.includes('passing_outcome');
|
|
995
|
+
var structuralChange = signals.some(function (signal) { return /blocker_fingerprint_changed|lane_changed|step_type_changed|failure_class_changed/.test(signal); });
|
|
996
|
+
var materialArtifact = addedArtifactPaths.length > 0 && pathOrSummaryHasMaterialSignal;
|
|
997
|
+
var materialChangedFiles = addedChangedFiles.length > 0
|
|
998
|
+
&& /diagnosis|owner|scope|diff|root.?cause|failing path|stack|trace|business|proof|compile|release|deploy|workflow|journey/i.test(evidenceText);
|
|
999
|
+
var material = proof || structuralChange || materialArtifact || materialChangedFiles;
|
|
1000
|
+
var strength = proof
|
|
1001
|
+
? 'proof'
|
|
1002
|
+
: material
|
|
1003
|
+
? 'material'
|
|
1004
|
+
: changed
|
|
1005
|
+
? 'weak'
|
|
1006
|
+
: 'none';
|
|
1007
|
+
return {
|
|
1008
|
+
changed: changed,
|
|
1009
|
+
material: material,
|
|
1010
|
+
strength: strength,
|
|
1011
|
+
signals: signals,
|
|
1012
|
+
evidenceHash: currentEvidenceHash,
|
|
1013
|
+
blockerFingerprint: currentBlockerFingerprint
|
|
1014
|
+
};
|
|
625
1015
|
}
|
|
626
1016
|
function proposedActionIsProductRepair(value) {
|
|
627
1017
|
var normalized = cleanText(value, 120);
|
|
@@ -632,16 +1022,21 @@ function decideResolveIOAIManagerRecoveryGate(input) {
|
|
|
632
1022
|
var checkpoint = input.checkpoint;
|
|
633
1023
|
var hasCurrent = !!input.current;
|
|
634
1024
|
var current = input.current || {};
|
|
635
|
-
var
|
|
636
|
-
?
|
|
637
|
-
:
|
|
638
|
-
|
|
1025
|
+
var assessment = hasCurrent
|
|
1026
|
+
? assessResolveIOAIManagerEvidenceChange(checkpoint, current, checkpoint.objective)
|
|
1027
|
+
: {
|
|
1028
|
+
changed: false,
|
|
1029
|
+
material: false,
|
|
1030
|
+
strength: 'none',
|
|
1031
|
+
signals: [],
|
|
1032
|
+
evidenceHash: checkpoint.evidenceHash,
|
|
1033
|
+
blockerFingerprint: checkpoint.blockerFingerprint
|
|
1034
|
+
};
|
|
1035
|
+
var blockerFingerprint = assessment.blockerFingerprint;
|
|
1036
|
+
var evidenceHash = assessment.evidenceHash;
|
|
639
1037
|
var changedFiles = hasCurrent ? cleanList(current.changedFiles, 80, 500) : checkpoint.changedFiles;
|
|
640
1038
|
var artifactPaths = hasCurrent ? cleanList(current.artifactPaths, 80, 500) : checkpoint.artifactPaths;
|
|
641
|
-
var evidenceChanged =
|
|
642
|
-
|| blockerFingerprint !== checkpoint.blockerFingerprint
|
|
643
|
-
|| listHasNewEntry(changedFiles, checkpoint.changedFiles)
|
|
644
|
-
|| listHasNewEntry(artifactPaths, checkpoint.artifactPaths);
|
|
1039
|
+
var evidenceChanged = assessment.changed;
|
|
645
1040
|
var proposedAction = cleanText(input.proposedAction || checkpoint.allowedAction, 120);
|
|
646
1041
|
var productRepairRequested = proposedActionIsProductRepair(proposedAction);
|
|
647
1042
|
var missingEvidence = checkpoint.requiredEvidence.filter(function (required) {
|
|
@@ -659,7 +1054,7 @@ function decideResolveIOAIManagerRecoveryGate(input) {
|
|
|
659
1054
|
});
|
|
660
1055
|
var makeDecision = function (action, reason, overrides) {
|
|
661
1056
|
if (overrides === void 0) { overrides = {}; }
|
|
662
|
-
return (__assign({ action: action, reason: reason, canRunProductRepair: checkpoint.productRepairAllowed, canRunExpensiveModel: checkpoint.expensiveModelAllowed, shouldResetLoopBudget: false, shouldIncrementAttempt: action === 'allow', newEvidence: evidenceChanged, blockerFingerprint: blockerFingerprint, evidenceHash: evidenceHash, missingEvidence: missingEvidence, checkpoint: __assign(__assign({}, checkpoint), { updatedAt: isoNow(input.now) }) }, overrides));
|
|
1057
|
+
return (__assign({ action: action, reason: reason, canRunProductRepair: checkpoint.productRepairAllowed, canRunExpensiveModel: checkpoint.expensiveModelAllowed, shouldResetLoopBudget: false, shouldIncrementAttempt: action === 'allow', newEvidence: evidenceChanged, materialEvidence: assessment.material, evidenceStrength: assessment.strength, evidenceSignals: assessment.signals, blockerFingerprint: blockerFingerprint, evidenceHash: evidenceHash, missingEvidence: missingEvidence, checkpoint: __assign(__assign({}, checkpoint), { updatedAt: isoNow(input.now) }) }, overrides));
|
|
663
1058
|
};
|
|
664
1059
|
if (checkpoint.status === 'complete') {
|
|
665
1060
|
return makeDecision('complete', 'recovery_gate_checkpoint_already_complete', {
|
|
@@ -689,6 +1084,13 @@ function decideResolveIOAIManagerRecoveryGate(input) {
|
|
|
689
1084
|
shouldIncrementAttempt: false
|
|
690
1085
|
});
|
|
691
1086
|
}
|
|
1087
|
+
if (checkpoint.status === 'parked' && evidenceChanged && !assessment.material) {
|
|
1088
|
+
return makeDecision('collect_new_evidence', 'recovery_gate_weak_evidence_requires_material_signal', {
|
|
1089
|
+
canRunProductRepair: false,
|
|
1090
|
+
canRunExpensiveModel: false,
|
|
1091
|
+
shouldIncrementAttempt: false
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
692
1094
|
if (checkpoint.attempts >= checkpoint.maxAttemptsBeforePark && !evidenceChanged) {
|
|
693
1095
|
return makeDecision('collect_new_evidence', 'recovery_gate_attempt_limit_requires_new_evidence', {
|
|
694
1096
|
canRunProductRepair: false,
|
|
@@ -696,11 +1098,18 @@ function decideResolveIOAIManagerRecoveryGate(input) {
|
|
|
696
1098
|
shouldIncrementAttempt: false
|
|
697
1099
|
});
|
|
698
1100
|
}
|
|
1101
|
+
if (checkpoint.attempts >= checkpoint.maxAttemptsBeforePark && evidenceChanged && !assessment.material) {
|
|
1102
|
+
return makeDecision('collect_new_evidence', 'recovery_gate_attempt_limit_requires_material_evidence', {
|
|
1103
|
+
canRunProductRepair: false,
|
|
1104
|
+
canRunExpensiveModel: false,
|
|
1105
|
+
shouldIncrementAttempt: false
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
699
1108
|
if (evidenceChanged) {
|
|
700
1109
|
var currentFailureClass = normalizeResolveIOAIManagerFailureClass(current.failureClass);
|
|
701
1110
|
var currentCanRunProductRepair = checkpoint.productRepairAllowed
|
|
702
1111
|
|| !/^(infra|compile|diagnosis|release)$/i.test(currentFailureClass);
|
|
703
|
-
return makeDecision('allow', '
|
|
1112
|
+
return makeDecision('allow', 'recovery_gate_new_material_evidence_unblocks_retry', {
|
|
704
1113
|
canRunProductRepair: currentCanRunProductRepair,
|
|
705
1114
|
canRunExpensiveModel: checkpoint.expensiveModelAllowed || currentCanRunProductRepair,
|
|
706
1115
|
shouldResetLoopBudget: true
|
|
@@ -812,8 +1221,8 @@ function buildResolveIOAIManagerRecoveryPlan(input) {
|
|
|
812
1221
|
'Do not rerun the same prompt or same repair.',
|
|
813
1222
|
'Show the repeated blocker and evidence hash.',
|
|
814
1223
|
'Collect a new artifact: failing DOM state, stack trace, network response, Mongo delta, compile log, or revised diagnosis.',
|
|
815
|
-
'Reset the loop only after the
|
|
816
|
-
], ['same failure count', 'blocker fingerprint', 'evidence hash'], ['changed
|
|
1224
|
+
'Reset the loop only after material evidence changes the blocker, proof, diagnosis, journey, or actionable trace.'
|
|
1225
|
+
], ['same failure count', 'blocker fingerprint', 'evidence hash'], ['changed blocker fingerprint', 'business/compile/infra/release proof artifact', 'revised diagnosis or journey contract', 'new actionable trace or data delta'], ['alternate between two failed patches', 'increase loop budget without evidence', 'hide the park reason']);
|
|
817
1226
|
}
|
|
818
1227
|
if (failureClass === 'journey') {
|
|
819
1228
|
return makePlan('journey_contract_repair', 'Repair Journey Contract', 'Fix the first/next/last workflow contract before app code work continues.', 'journey_contract_repair', false, true, [
|
|
@@ -824,12 +1233,12 @@ function buildResolveIOAIManagerRecoveryPlan(input) {
|
|
|
824
1233
|
], ['validated journey_contract JSON', 'CTA-to-action mapping', 'workflow QA assertions'], ['journey validation passes', 'new workflow QA rows generated'], ['build empty routes', 'add link-only dashboard actions', 'defer workflow design to wow pass']);
|
|
825
1234
|
}
|
|
826
1235
|
if (failureClass === 'release') {
|
|
827
|
-
return makePlan('release_repair', 'Repair Release Gate', 'Repair deploy/publish/sample-data release evidence
|
|
1236
|
+
return makePlan('release_repair', 'Repair Release Gate', 'Repair deploy/publish/sample-data release evidence with a hotfix-first path before any repeated full deploy.', 'release_repair_only', false, false, [
|
|
828
1237
|
'Read the deploy/publish/sample-data log.',
|
|
829
1238
|
'Identify whether the blocker is domain, asset, seed data, route, permission, or CDN.',
|
|
830
|
-
'
|
|
1239
|
+
'Prefer backend hotfix, release config, domain, cache, or seed-data repair when the product artifact already has business proof.',
|
|
831
1240
|
'Rerun only the failed release gate.'
|
|
832
|
-
], ['deploy or publish log', 'sample-data status', 'failed release gate rerun'], ['release gate passes', 'new release blocker hash'], ['change core workflow after business QA passed', 'mark accepted from scorecard only', 'rerun full builder loop']);
|
|
1241
|
+
], ['deploy or publish log', 'sample-data status', 'failed release gate rerun'], ['release gate passes', 'new release blocker hash'], ['change core workflow after business QA passed', 'mark accepted from scorecard only', 'rerun full builder loop', 'repeat deploy of same artifact without force_deploy evidence']);
|
|
833
1242
|
}
|
|
834
1243
|
if (failureClass === 'business' || failureClass === 'qa_evidence' || failureClass === 'route') {
|
|
835
1244
|
return makePlan('business_proof_repair', 'Repair Business Proof', 'Fix the exact failing workflow assertion and prove before/action/after behavior.', 'business_repair', true, true, [
|
|
@@ -867,20 +1276,33 @@ function collectOpenTail(records) {
|
|
|
867
1276
|
return tail;
|
|
868
1277
|
}
|
|
869
1278
|
function countSameFailure(records, current) {
|
|
870
|
-
var currentKey =
|
|
1279
|
+
var currentKey = failureKey(current);
|
|
871
1280
|
var count = 0;
|
|
872
1281
|
for (var index = records.length - 1; index >= 0; index -= 1) {
|
|
873
1282
|
var record = records[index];
|
|
874
1283
|
if (isPassingOutcome(record)) {
|
|
875
1284
|
break;
|
|
876
1285
|
}
|
|
877
|
-
if (
|
|
1286
|
+
if (failureKey(record) !== currentKey) {
|
|
878
1287
|
break;
|
|
879
1288
|
}
|
|
880
1289
|
count += 1;
|
|
881
1290
|
}
|
|
882
1291
|
return count;
|
|
883
1292
|
}
|
|
1293
|
+
function previousRecordForPolicy(history, current, currentWasExplicit) {
|
|
1294
|
+
if (!history.length) {
|
|
1295
|
+
return undefined;
|
|
1296
|
+
}
|
|
1297
|
+
if (!currentWasExplicit) {
|
|
1298
|
+
return history.length > 1 ? history[history.length - 2] : undefined;
|
|
1299
|
+
}
|
|
1300
|
+
var last = history[history.length - 1];
|
|
1301
|
+
if (failureEvidenceKey(last) === failureEvidenceKey(current)) {
|
|
1302
|
+
return history.length > 1 ? history[history.length - 2] : undefined;
|
|
1303
|
+
}
|
|
1304
|
+
return last;
|
|
1305
|
+
}
|
|
884
1306
|
function countPingPong(records, current) {
|
|
885
1307
|
var tail = collectOpenTail(records).filter(function (record) {
|
|
886
1308
|
return cleanText(record.lane, 80) === cleanText(current.lane, 80)
|
|
@@ -907,14 +1329,24 @@ function countPingPong(records, current) {
|
|
|
907
1329
|
}
|
|
908
1330
|
function decideResolveIOAIManagerPolicy(input) {
|
|
909
1331
|
var history = Array.isArray(input.history) ? input.history : [];
|
|
1332
|
+
var currentWasExplicit = !!input.current;
|
|
910
1333
|
var current = input.current || history[history.length - 1] || {};
|
|
911
1334
|
var failureClass = normalizeResolveIOAIManagerFailureClass(current.failureClass);
|
|
912
1335
|
var blockerFingerprint = resolveResolveIOAIManagerBlockerFingerprint(current);
|
|
913
1336
|
var evidenceHash = hashResolveIOAIManagerEvidence(current);
|
|
914
|
-
var previous = history
|
|
1337
|
+
var previous = previousRecordForPolicy(history, current, currentWasExplicit);
|
|
915
1338
|
var previousSameFailure = previous && failureKey(previous) === failureKey(current);
|
|
916
|
-
var
|
|
917
|
-
|
|
1339
|
+
var evidenceAssessment = previousSameFailure
|
|
1340
|
+
? assessResolveIOAIManagerEvidenceChange(previous, current)
|
|
1341
|
+
: {
|
|
1342
|
+
changed: false,
|
|
1343
|
+
material: false,
|
|
1344
|
+
strength: 'none',
|
|
1345
|
+
signals: [],
|
|
1346
|
+
evidenceHash: evidenceHash,
|
|
1347
|
+
blockerFingerprint: blockerFingerprint
|
|
1348
|
+
};
|
|
1349
|
+
var newEvidence = !!previousSameFailure && evidenceAssessment.changed;
|
|
918
1350
|
var sameFailureCount = countSameFailure(history, current);
|
|
919
1351
|
var pingPongCount = countPingPong(history, current);
|
|
920
1352
|
var maxSameFailureRepeats = Math.max(1, Number(input.maxSameFailureRepeats || 3) || 3);
|
|
@@ -928,6 +1360,9 @@ function decideResolveIOAIManagerPolicy(input) {
|
|
|
928
1360
|
sameFailureCount: sameFailureCount,
|
|
929
1361
|
pingPongCount: pingPongCount,
|
|
930
1362
|
newEvidence: newEvidence,
|
|
1363
|
+
materialEvidence: evidenceAssessment.material,
|
|
1364
|
+
evidenceStrength: evidenceAssessment.strength,
|
|
1365
|
+
evidenceSignals: evidenceAssessment.signals,
|
|
931
1366
|
loopBudgetShouldReset: false,
|
|
932
1367
|
productRepairFailure: !infraClasses.has(failureClass) && !ignoredClasses.has(failureClass)
|
|
933
1368
|
};
|
|
@@ -976,8 +1411,10 @@ function decideResolveIOAIManagerPolicy(input) {
|
|
|
976
1411
|
if (pingPongCount >= maxPingPongTransitions) {
|
|
977
1412
|
return withPlan('park_ping_pong', 'manager_policy_ping_pong_failure_loop');
|
|
978
1413
|
}
|
|
979
|
-
if (sameFailureCount >= maxSameFailureRepeats && !
|
|
980
|
-
return withPlan('park_repeated_failure',
|
|
1414
|
+
if (sameFailureCount >= maxSameFailureRepeats && !evidenceAssessment.material) {
|
|
1415
|
+
return withPlan('park_repeated_failure', newEvidence
|
|
1416
|
+
? 'manager_policy_same_failure_with_weak_evidence'
|
|
1417
|
+
: 'manager_policy_same_failure_without_new_evidence');
|
|
981
1418
|
}
|
|
982
1419
|
if (infraClasses.has(failureClass)) {
|
|
983
1420
|
return withPlan('retry_infra', 'manager_policy_infra_failure_routes_to_infra_repair', {
|
|
@@ -985,13 +1422,311 @@ function decideResolveIOAIManagerPolicy(input) {
|
|
|
985
1422
|
});
|
|
986
1423
|
}
|
|
987
1424
|
if (newEvidence || !previousSameFailure) {
|
|
1425
|
+
if (newEvidence && !evidenceAssessment.material) {
|
|
1426
|
+
return withPlan('continue', 'manager_policy_weak_evidence_does_not_reset_loop_budget');
|
|
1427
|
+
}
|
|
988
1428
|
return withPlan('continue', newEvidence
|
|
989
|
-
? '
|
|
1429
|
+
? 'manager_policy_new_material_evidence_resets_loop_budget'
|
|
990
1430
|
: 'manager_policy_new_failure_or_lane', {
|
|
991
|
-
loopBudgetShouldReset: true
|
|
1431
|
+
loopBudgetShouldReset: true,
|
|
1432
|
+
materialEvidence: newEvidence ? true : base.materialEvidence,
|
|
1433
|
+
evidenceStrength: newEvidence ? evidenceAssessment.strength : base.evidenceStrength
|
|
992
1434
|
});
|
|
993
1435
|
}
|
|
994
1436
|
return withPlan('continue', 'manager_policy_retry_below_repeat_limit');
|
|
995
1437
|
}
|
|
1438
|
+
function buildReplayDirectiveFromPlan(input) {
|
|
1439
|
+
var checkpoint = buildResolveIOAIManagerRecoveryCheckpoint({
|
|
1440
|
+
plan: input.plan,
|
|
1441
|
+
current: input.current,
|
|
1442
|
+
now: input.now
|
|
1443
|
+
});
|
|
1444
|
+
var probe = buildResolveIOAIManagerRecoveryEvidenceProbe({
|
|
1445
|
+
checkpoint: checkpoint,
|
|
1446
|
+
current: input.current,
|
|
1447
|
+
now: input.now
|
|
1448
|
+
});
|
|
1449
|
+
var action = buildResolveIOAIManagerRecoveryActionPacket({
|
|
1450
|
+
plan: input.plan,
|
|
1451
|
+
checkpoint: checkpoint,
|
|
1452
|
+
probe: probe,
|
|
1453
|
+
current: input.current,
|
|
1454
|
+
now: input.now
|
|
1455
|
+
});
|
|
1456
|
+
var dispatch = decideResolveIOAIManagerRecoveryActionDispatch({
|
|
1457
|
+
action: action,
|
|
1458
|
+
current: input.current,
|
|
1459
|
+
now: input.now
|
|
1460
|
+
});
|
|
1461
|
+
return buildResolveIOAIManagerRecoveryExecutionDirective({
|
|
1462
|
+
action: action,
|
|
1463
|
+
dispatchDecision: dispatch,
|
|
1464
|
+
current: input.current,
|
|
1465
|
+
surface: input.surface,
|
|
1466
|
+
now: input.now
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
function replayCaseFromDirective(input) {
|
|
1470
|
+
var _a;
|
|
1471
|
+
var directive = input.directive;
|
|
1472
|
+
var safeAutoDispatch = isResolveIOAIManagerSafeAutoDispatch({
|
|
1473
|
+
dispatchAction: directive.dispatchAction,
|
|
1474
|
+
directive: directive,
|
|
1475
|
+
includeJourneyContractRepair: input.expectedSafeAutoDispatch && directive.dispatchAction === 'run_journey_contract_repair',
|
|
1476
|
+
includeReleaseRepair: input.expectedSafeAutoDispatch && directive.dispatchAction === 'run_release_repair',
|
|
1477
|
+
includeProductRepair: false
|
|
1478
|
+
});
|
|
1479
|
+
return __assign(__assign({ caseId: input.caseId, surface: input.surface, pass: input.pass && safeAutoDispatch === input.expectedSafeAutoDispatch, action: input.action, reason: input.reason, recoveryClass: cleanText(((_a = directive.dispatchRecord) === null || _a === void 0 ? void 0 : _a.mode) || directive.phase, 120), dispatchAction: directive.dispatchAction, safeAutoDispatch: safeAutoDispatch, expectedSafeAutoDispatch: input.expectedSafeAutoDispatch, productRepairAllowed: directive.canRunProductRepair === true, loopBudgetShouldReset: input.loopBudgetShouldReset === true, materialEvidence: input.materialEvidence === true, evidenceStrength: input.evidenceStrength || 'none' }, (directive.releasePolicy ? {
|
|
1480
|
+
hotfixFirst: directive.releasePolicy.policy === 'hotfix_first',
|
|
1481
|
+
fullDeployAllowed: directive.releasePolicy.fullDeployAllowed
|
|
1482
|
+
} : {})), { details: __assign({ phase: directive.phase, allowed: directive.allowed, reason: directive.reason, releasePolicy: directive.releasePolicy }, (input.details || {})) });
|
|
1483
|
+
}
|
|
1484
|
+
function buildResolveIOAIManagerRecoveryReplayMatrix(input) {
|
|
1485
|
+
var _a, _b;
|
|
1486
|
+
if (input === void 0) { input = {}; }
|
|
1487
|
+
var surface = cleanText(input.surface || 'runner', 120);
|
|
1488
|
+
var maxSameFailureRepeats = Math.max(1, Number(input.maxSameFailureRepeats || 2) || 2);
|
|
1489
|
+
var includeReleaseRepair = input.includeReleaseRepair !== false;
|
|
1490
|
+
var includeJourneyContractRepair = input.includeJourneyContractRepair !== false;
|
|
1491
|
+
var cases = [];
|
|
1492
|
+
var infraPolicy = decideResolveIOAIManagerPolicy({
|
|
1493
|
+
history: [
|
|
1494
|
+
{ lane: 'qa', stepType: 'workflow_qa', outcome: 'needs_repair', failureClass: 'infra', blocker: 'Chrome executable missing.', evidenceHash: 'chrome-missing' }
|
|
1495
|
+
],
|
|
1496
|
+
current: { lane: 'qa', stepType: 'workflow_qa', outcome: 'needs_repair', failureClass: 'infra', blocker: 'Chrome executable missing.', evidenceHash: 'chrome-missing' },
|
|
1497
|
+
maxSameFailureRepeats: maxSameFailureRepeats
|
|
1498
|
+
});
|
|
1499
|
+
var infraDirective = buildResolveIOAIManagerRecoveryExecutionDirective({
|
|
1500
|
+
action: infraPolicy.recoveryAction,
|
|
1501
|
+
current: { lane: 'qa', stepType: 'workflow_qa', outcome: 'needs_repair', failureClass: 'infra', blocker: 'Chrome executable missing.', evidenceHash: 'chrome-missing' },
|
|
1502
|
+
surface: surface
|
|
1503
|
+
});
|
|
1504
|
+
cases.push(replayCaseFromDirective({
|
|
1505
|
+
caseId: 'infra_routes_to_infra_repair',
|
|
1506
|
+
surface: surface,
|
|
1507
|
+
action: infraPolicy.action,
|
|
1508
|
+
reason: infraPolicy.reason,
|
|
1509
|
+
directive: infraDirective,
|
|
1510
|
+
expectedSafeAutoDispatch: true,
|
|
1511
|
+
pass: infraPolicy.action === 'retry_infra'
|
|
1512
|
+
&& infraPolicy.recoveryPlan.recoveryClass === 'infra_repair'
|
|
1513
|
+
&& infraDirective.dispatchAction === 'run_infra_repair'
|
|
1514
|
+
&& infraDirective.canRunProductRepair === false,
|
|
1515
|
+
details: { recoveryClass: infraPolicy.recoveryPlan.recoveryClass }
|
|
1516
|
+
}));
|
|
1517
|
+
var releasePlan = buildResolveIOAIManagerRecoveryPlan({
|
|
1518
|
+
action: 'continue',
|
|
1519
|
+
reason: 'publish failed after business proof',
|
|
1520
|
+
failureClass: 'release',
|
|
1521
|
+
lane: 'publish',
|
|
1522
|
+
stepType: 'test_deploy',
|
|
1523
|
+
blocker: 'Domain publish failed for the current artifact.'
|
|
1524
|
+
});
|
|
1525
|
+
var releaseCurrent = {
|
|
1526
|
+
lane: 'publish',
|
|
1527
|
+
stepType: 'test_deploy',
|
|
1528
|
+
outcome: 'needs_repair',
|
|
1529
|
+
failureClass: 'release',
|
|
1530
|
+
blocker: 'Domain publish failed for the current artifact.',
|
|
1531
|
+
evidenceHash: 'release-domain-publish-failed',
|
|
1532
|
+
artifactPaths: ['runner-evidence/release-status.json']
|
|
1533
|
+
};
|
|
1534
|
+
var releaseDirective = buildReplayDirectiveFromPlan({
|
|
1535
|
+
surface: surface,
|
|
1536
|
+
plan: releasePlan,
|
|
1537
|
+
current: releaseCurrent
|
|
1538
|
+
});
|
|
1539
|
+
cases.push(replayCaseFromDirective({
|
|
1540
|
+
caseId: 'release_uses_hotfix_first_repair',
|
|
1541
|
+
surface: surface,
|
|
1542
|
+
action: 'continue',
|
|
1543
|
+
reason: 'publish failed after business proof',
|
|
1544
|
+
directive: releaseDirective,
|
|
1545
|
+
expectedSafeAutoDispatch: includeReleaseRepair,
|
|
1546
|
+
pass: releasePlan.recoveryClass === 'release_repair'
|
|
1547
|
+
&& releaseDirective.dispatchAction === 'run_release_repair'
|
|
1548
|
+
&& ((_a = releaseDirective.releasePolicy) === null || _a === void 0 ? void 0 : _a.policy) === 'hotfix_first'
|
|
1549
|
+
&& ((_b = releaseDirective.releasePolicy) === null || _b === void 0 ? void 0 : _b.fullDeployAllowed) === false
|
|
1550
|
+
&& releaseDirective.canRunProductRepair === false,
|
|
1551
|
+
details: { recoveryClass: releasePlan.recoveryClass }
|
|
1552
|
+
}));
|
|
1553
|
+
var journeyPlan = buildResolveIOAIManagerRecoveryPlan({
|
|
1554
|
+
action: 'continue',
|
|
1555
|
+
reason: 'journey contract missing first next last',
|
|
1556
|
+
failureClass: 'journey',
|
|
1557
|
+
lane: 'plan',
|
|
1558
|
+
stepType: 'journey_contract',
|
|
1559
|
+
blocker: 'Journey contract does not map the hub CTA to an action.'
|
|
1560
|
+
});
|
|
1561
|
+
var journeyDirective = buildReplayDirectiveFromPlan({
|
|
1562
|
+
surface: surface,
|
|
1563
|
+
plan: journeyPlan,
|
|
1564
|
+
current: {
|
|
1565
|
+
lane: 'plan',
|
|
1566
|
+
stepType: 'journey_contract',
|
|
1567
|
+
outcome: 'needs_repair',
|
|
1568
|
+
failureClass: 'journey',
|
|
1569
|
+
blocker: 'Journey contract does not map the hub CTA to an action.',
|
|
1570
|
+
evidenceHash: 'journey-contract-invalid'
|
|
1571
|
+
}
|
|
1572
|
+
});
|
|
1573
|
+
cases.push(replayCaseFromDirective({
|
|
1574
|
+
caseId: 'journey_repair_is_safe_only_for_aicoder_surfaces',
|
|
1575
|
+
surface: surface,
|
|
1576
|
+
action: 'continue',
|
|
1577
|
+
reason: 'journey contract missing first next last',
|
|
1578
|
+
directive: journeyDirective,
|
|
1579
|
+
expectedSafeAutoDispatch: includeJourneyContractRepair,
|
|
1580
|
+
pass: journeyPlan.recoveryClass === 'journey_contract_repair'
|
|
1581
|
+
&& journeyDirective.dispatchAction === 'run_journey_contract_repair'
|
|
1582
|
+
&& journeyDirective.canRunProductRepair === false,
|
|
1583
|
+
details: { recoveryClass: journeyPlan.recoveryClass }
|
|
1584
|
+
}));
|
|
1585
|
+
var weakPolicy = decideResolveIOAIManagerPolicy({
|
|
1586
|
+
history: [
|
|
1587
|
+
{ lane: 'repair', stepType: 'repair', outcome: 'needs_repair', failureClass: 'product_code', blocker: 'Save action still throws TypeError.', evidenceHash: 'save-before' },
|
|
1588
|
+
{ lane: 'repair', stepType: 'repair', outcome: 'needs_repair', failureClass: 'product_code', blocker: 'Save action still throws TypeError.', evidenceHash: 'renamed-hash-only' }
|
|
1589
|
+
],
|
|
1590
|
+
current: { lane: 'repair', stepType: 'repair', outcome: 'needs_repair', failureClass: 'product_code', blocker: 'Save action still throws TypeError.', evidenceHash: 'renamed-hash-only' },
|
|
1591
|
+
maxSameFailureRepeats: maxSameFailureRepeats
|
|
1592
|
+
});
|
|
1593
|
+
var weakDirective = buildResolveIOAIManagerRecoveryExecutionDirective({
|
|
1594
|
+
action: weakPolicy.recoveryAction,
|
|
1595
|
+
current: { lane: 'repair', stepType: 'repair', outcome: 'needs_repair', failureClass: 'product_code', blocker: 'Save action still throws TypeError.', evidenceHash: 'renamed-hash-only' },
|
|
1596
|
+
surface: surface
|
|
1597
|
+
});
|
|
1598
|
+
cases.push(replayCaseFromDirective({
|
|
1599
|
+
caseId: 'weak_hash_only_evidence_stays_parked',
|
|
1600
|
+
surface: surface,
|
|
1601
|
+
action: weakPolicy.action,
|
|
1602
|
+
reason: weakPolicy.reason,
|
|
1603
|
+
directive: weakDirective,
|
|
1604
|
+
expectedSafeAutoDispatch: true,
|
|
1605
|
+
pass: weakPolicy.action === 'park_repeated_failure'
|
|
1606
|
+
&& weakPolicy.materialEvidence === false
|
|
1607
|
+
&& weakPolicy.loopBudgetShouldReset === false
|
|
1608
|
+
&& weakDirective.dispatchAction === 'run_evidence_probe',
|
|
1609
|
+
loopBudgetShouldReset: weakPolicy.loopBudgetShouldReset,
|
|
1610
|
+
materialEvidence: weakPolicy.materialEvidence,
|
|
1611
|
+
evidenceStrength: weakPolicy.evidenceStrength,
|
|
1612
|
+
details: { evidenceSignals: weakPolicy.evidenceSignals }
|
|
1613
|
+
}));
|
|
1614
|
+
var materialPolicy = decideResolveIOAIManagerPolicy({
|
|
1615
|
+
history: [
|
|
1616
|
+
{ lane: 'repair', stepType: 'repair', outcome: 'needs_repair', failureClass: 'product_code', blocker: 'Save action still throws TypeError.', evidenceHash: 'save-before', artifactPaths: ['qa/save-before.log'] },
|
|
1617
|
+
{
|
|
1618
|
+
lane: 'repair',
|
|
1619
|
+
stepType: 'repair',
|
|
1620
|
+
outcome: 'needs_repair',
|
|
1621
|
+
failureClass: 'product_code',
|
|
1622
|
+
blocker: 'Save action still throws TypeError.',
|
|
1623
|
+
summary: 'New DOM trace proves the click reaches the method with an undefined id.',
|
|
1624
|
+
evidenceHash: 'save-dom-trace',
|
|
1625
|
+
artifactPaths: ['qa/save-before.log', 'qa/save-dom-trace.json']
|
|
1626
|
+
}
|
|
1627
|
+
],
|
|
1628
|
+
current: {
|
|
1629
|
+
lane: 'repair',
|
|
1630
|
+
stepType: 'repair',
|
|
1631
|
+
outcome: 'needs_repair',
|
|
1632
|
+
failureClass: 'product_code',
|
|
1633
|
+
blocker: 'Save action still throws TypeError.',
|
|
1634
|
+
summary: 'New DOM trace proves the click reaches the method with an undefined id.',
|
|
1635
|
+
evidenceHash: 'save-dom-trace',
|
|
1636
|
+
artifactPaths: ['qa/save-before.log', 'qa/save-dom-trace.json']
|
|
1637
|
+
},
|
|
1638
|
+
maxSameFailureRepeats: maxSameFailureRepeats
|
|
1639
|
+
});
|
|
1640
|
+
cases.push({
|
|
1641
|
+
caseId: 'material_evidence_resets_loop_budget',
|
|
1642
|
+
surface: surface,
|
|
1643
|
+
pass: materialPolicy.action === 'continue'
|
|
1644
|
+
&& materialPolicy.materialEvidence === true
|
|
1645
|
+
&& materialPolicy.loopBudgetShouldReset === true,
|
|
1646
|
+
action: materialPolicy.action,
|
|
1647
|
+
reason: materialPolicy.reason,
|
|
1648
|
+
recoveryClass: materialPolicy.recoveryPlan.recoveryClass,
|
|
1649
|
+
dispatchAction: materialPolicy.recoveryAction.mode,
|
|
1650
|
+
safeAutoDispatch: false,
|
|
1651
|
+
expectedSafeAutoDispatch: false,
|
|
1652
|
+
productRepairAllowed: materialPolicy.recoveryAction.productRepairAllowed,
|
|
1653
|
+
loopBudgetShouldReset: materialPolicy.loopBudgetShouldReset,
|
|
1654
|
+
materialEvidence: materialPolicy.materialEvidence,
|
|
1655
|
+
evidenceStrength: materialPolicy.evidenceStrength,
|
|
1656
|
+
details: { evidenceSignals: materialPolicy.evidenceSignals }
|
|
1657
|
+
});
|
|
1658
|
+
var productPlan = buildResolveIOAIManagerRecoveryPlan({
|
|
1659
|
+
action: 'continue',
|
|
1660
|
+
reason: 'business proof still failing',
|
|
1661
|
+
failureClass: 'product_code',
|
|
1662
|
+
lane: 'repair',
|
|
1663
|
+
stepType: 'repair',
|
|
1664
|
+
blocker: 'Save action still throws TypeError.',
|
|
1665
|
+
productRepairFailure: true
|
|
1666
|
+
});
|
|
1667
|
+
var productDirective = buildReplayDirectiveFromPlan({
|
|
1668
|
+
surface: surface,
|
|
1669
|
+
plan: productPlan,
|
|
1670
|
+
current: {
|
|
1671
|
+
lane: 'repair',
|
|
1672
|
+
stepType: 'repair',
|
|
1673
|
+
outcome: 'needs_repair',
|
|
1674
|
+
failureClass: 'product_code',
|
|
1675
|
+
blocker: 'Save action still throws TypeError.',
|
|
1676
|
+
evidenceHash: 'save-product-repair'
|
|
1677
|
+
}
|
|
1678
|
+
});
|
|
1679
|
+
var productSafe = isResolveIOAIManagerSafeAutoDispatch({
|
|
1680
|
+
dispatchAction: productDirective.dispatchAction,
|
|
1681
|
+
directive: productDirective,
|
|
1682
|
+
includeProductRepair: input.includeProductRepair === true
|
|
1683
|
+
});
|
|
1684
|
+
cases.push({
|
|
1685
|
+
caseId: 'product_repair_requires_explicit_operator_policy',
|
|
1686
|
+
surface: surface,
|
|
1687
|
+
pass: productPlan.recoveryClass === 'product_code_repair'
|
|
1688
|
+
&& productDirective.dispatchAction === 'run_targeted_product_repair'
|
|
1689
|
+
&& productSafe === false,
|
|
1690
|
+
action: 'continue',
|
|
1691
|
+
reason: 'business proof still failing',
|
|
1692
|
+
recoveryClass: productPlan.recoveryClass,
|
|
1693
|
+
dispatchAction: productDirective.dispatchAction,
|
|
1694
|
+
safeAutoDispatch: productSafe,
|
|
1695
|
+
expectedSafeAutoDispatch: false,
|
|
1696
|
+
productRepairAllowed: productDirective.canRunProductRepair,
|
|
1697
|
+
loopBudgetShouldReset: false,
|
|
1698
|
+
materialEvidence: false,
|
|
1699
|
+
evidenceStrength: 'none',
|
|
1700
|
+
details: { phase: productDirective.phase, allowed: productDirective.allowed }
|
|
1701
|
+
});
|
|
1702
|
+
var duplicateReleasePolicy = buildResolveIOAIManagerHotfixFirstReleasePolicy({
|
|
1703
|
+
surface: surface,
|
|
1704
|
+
deployFingerprint: "".concat(surface, "-artifact-sha"),
|
|
1705
|
+
lastDeployFingerprint: "".concat(surface, "-artifact-sha"),
|
|
1706
|
+
deployStatus: 'completed',
|
|
1707
|
+
publishStatus: 'published'
|
|
1708
|
+
});
|
|
1709
|
+
cases.push({
|
|
1710
|
+
caseId: 'duplicate_release_fingerprint_blocks_full_deploy',
|
|
1711
|
+
surface: surface,
|
|
1712
|
+
pass: duplicateReleasePolicy.recommendedAction === 'block_duplicate_deploy'
|
|
1713
|
+
&& duplicateReleasePolicy.duplicateDeployBlocked === true
|
|
1714
|
+
&& duplicateReleasePolicy.fullDeployAllowed === false,
|
|
1715
|
+
action: duplicateReleasePolicy.recommendedAction,
|
|
1716
|
+
reason: duplicateReleasePolicy.reason,
|
|
1717
|
+
recoveryClass: 'release_repair',
|
|
1718
|
+
dispatchAction: 'run_release_repair',
|
|
1719
|
+
safeAutoDispatch: includeReleaseRepair,
|
|
1720
|
+
expectedSafeAutoDispatch: includeReleaseRepair,
|
|
1721
|
+
productRepairAllowed: false,
|
|
1722
|
+
loopBudgetShouldReset: false,
|
|
1723
|
+
materialEvidence: false,
|
|
1724
|
+
evidenceStrength: 'none',
|
|
1725
|
+
hotfixFirst: true,
|
|
1726
|
+
fullDeployAllowed: duplicateReleasePolicy.fullDeployAllowed,
|
|
1727
|
+
details: { releasePolicy: duplicateReleasePolicy }
|
|
1728
|
+
});
|
|
1729
|
+
return cases;
|
|
1730
|
+
}
|
|
996
1731
|
|
|
997
1732
|
//# sourceMappingURL=ai-runner-manager-policy.js.map
|