@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.
@@ -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 ? ['changed evidence hash', 'new artifact path'] : [])), false).map(function (entry) { return cleanText(entry, 500); }).filter(Boolean))).slice(0, 30);
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: nextCommands, successCriteria: probe.acceptanceEvidence.slice(0, 20), retryPolicy: {
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
- : ['Do not run product-code repair from this directive unless canRunProductRepair is true.'] }, (dispatchDecision.dispatchRecord ? { dispatchRecord: dispatchDecision.dispatchRecord } : {})), { createdAt: now });
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 listHasNewEntry(current, previous) {
925
+ function newListEntries(current, previous) {
620
926
  var existing = new Set(previous.map(function (entry) { return cleanText(entry, 500); }).filter(Boolean));
621
- return current.some(function (entry) {
622
- var normalized = cleanText(entry, 500);
623
- return !!normalized && !existing.has(normalized);
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 blockerFingerprint = hasCurrent
636
- ? resolveResolveIOAIManagerBlockerFingerprint(current, checkpoint.objective)
637
- : checkpoint.blockerFingerprint;
638
- var evidenceHash = hasCurrent ? hashResolveIOAIManagerEvidence(current) : checkpoint.evidenceHash;
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 = evidenceHash !== checkpoint.evidenceHash
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', 'recovery_gate_new_evidence_unblocks_retry', {
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 new evidence hash changes.'
816
- ], ['same failure count', 'blocker fingerprint', 'evidence hash'], ['changed evidence hash', 'new artifact path', 'revised diagnosis or journey contract'], ['alternate between two failed patches', 'increase loop budget without evidence', 'hide the park reason']);
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 without rewriting working app flow.', 'release_repair_only', false, false, [
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
- 'Repair the release artifact/config/seed issue.',
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 = failureEvidenceKey(current);
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 (failureEvidenceKey(record) !== currentKey) {
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.length > 1 ? history[history.length - 2] : undefined;
1337
+ var previous = previousRecordForPolicy(history, current, currentWasExplicit);
915
1338
  var previousSameFailure = previous && failureKey(previous) === failureKey(current);
916
- var previousEvidenceHash = previousSameFailure ? hashResolveIOAIManagerEvidence(previous) : '';
917
- var newEvidence = !!previousSameFailure && !!previousEvidenceHash && previousEvidenceHash !== evidenceHash;
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 && !newEvidence) {
980
- return withPlan('park_repeated_failure', 'manager_policy_same_failure_without_new_evidence');
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
- ? 'manager_policy_new_evidence_resets_loop_budget'
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