@resolveio/server-lib 22.3.158 → 22.3.159

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,9 +47,14 @@ 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.estimateResolveIOAIManagerRetryExpectedValue = estimateResolveIOAIManagerRetryExpectedValue;
51
+ exports.decideResolveIOAIManagerAutonomyPolicy = decideResolveIOAIManagerAutonomyPolicy;
50
52
  exports.normalizeResolveIOAIManagerHotfixEvidence = normalizeResolveIOAIManagerHotfixEvidence;
53
+ exports.evaluateResolveIOAIManagerHotfixGitProof = evaluateResolveIOAIManagerHotfixGitProof;
51
54
  exports.validateResolveIOAIManagerHotfixEvidence = validateResolveIOAIManagerHotfixEvidence;
55
+ exports.buildResolveIOAIManagerHotfixEvidenceRecord = buildResolveIOAIManagerHotfixEvidenceRecord;
52
56
  exports.decideResolveIOAIManagerHotfixContinuation = decideResolveIOAIManagerHotfixContinuation;
57
+ exports.decideResolveIOAIManagerHotfixCommitGuard = decideResolveIOAIManagerHotfixCommitGuard;
53
58
  exports.buildResolveIOAIManagerHotfixFirstReleasePolicy = buildResolveIOAIManagerHotfixFirstReleasePolicy;
54
59
  exports.isResolveIOAIManagerSafeAutoDispatch = isResolveIOAIManagerSafeAutoDispatch;
55
60
  exports.normalizeResolveIOAIManagerFailureClass = normalizeResolveIOAIManagerFailureClass;
@@ -114,6 +119,291 @@ var HOTFIX_CHANNELS = new Set([
114
119
  function cleanObject(value) {
115
120
  return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
116
121
  }
122
+ function normalizeAutonomyMode(value) {
123
+ var normalized = cleanText(value, 120).toLowerCase().replace(/[\s-]+/g, '_');
124
+ if (/^(monitor|monitor_only|watch|watch_only)$/.test(normalized)) {
125
+ return 'monitor_only';
126
+ }
127
+ if (/^(auto|auto_retry|auto_retry_within_budget|autonomous|within_budget)$/.test(normalized)) {
128
+ return 'auto_retry_within_budget';
129
+ }
130
+ return 'manual_only';
131
+ }
132
+ function normalizeManagerEvidenceStrength(value) {
133
+ var normalized = cleanText(value, 40).toLowerCase().replace(/[\s-]+/g, '_');
134
+ if (normalized === 'proof') {
135
+ return 'proof';
136
+ }
137
+ if (normalized === 'material' || normalized === 'strong') {
138
+ return 'material';
139
+ }
140
+ if (normalized === 'weak') {
141
+ return 'weak';
142
+ }
143
+ return 'none';
144
+ }
145
+ function nonNegativeMoney(value) {
146
+ var parsed = Number(value);
147
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
148
+ }
149
+ function finiteNumber(value) {
150
+ var parsed = Number(value);
151
+ return Number.isFinite(parsed) ? parsed : undefined;
152
+ }
153
+ function clampNumber(value, min, max) {
154
+ return Math.min(max, Math.max(min, value));
155
+ }
156
+ function isCheapEvidenceAutonomyAction(value) {
157
+ var action = cleanText(value, 120);
158
+ return !action || /^(run_evidence_probe|run_read_only_diagnosis|advance|continue_gate|park_manual)$/.test(action);
159
+ }
160
+ function estimateResolveIOAIManagerRetryExpectedValue(input) {
161
+ var e_2, _a;
162
+ if (input === void 0) { input = {}; }
163
+ var dispatchAction = cleanText(input.dispatchAction, 120);
164
+ var failureClass = normalizeResolveIOAIManagerFailureClass(input.failureClass);
165
+ var recoveryClass = cleanText(input.recoveryClass, 120);
166
+ var evidenceStrength = normalizeManagerEvidenceStrength(input.evidenceStrength);
167
+ var evidenceSignals = cleanList(input.evidenceSignals, 12, 120);
168
+ var projectedActionCostUsd = nonNegativeMoney(input.projectedActionCostUsd);
169
+ var budgetHardUsd = nonNegativeMoney(input.budgetHardUsd);
170
+ var materialEvidence = input.materialEvidence === true || evidenceStrength === 'material' || evidenceStrength === 'proof';
171
+ var newEvidence = input.newEvidence === true;
172
+ var signals = [];
173
+ var score = 0.1;
174
+ if (dispatchAction === 'run_evidence_probe') {
175
+ score = 0.75;
176
+ signals.push('cheap_evidence_probe');
177
+ }
178
+ else if (dispatchAction === 'run_read_only_diagnosis') {
179
+ score = 0.65;
180
+ signals.push('read_only_diagnosis');
181
+ }
182
+ else if (dispatchAction === 'advance' || dispatchAction === 'continue_gate') {
183
+ score = 0.55;
184
+ signals.push('gate_continuation');
185
+ }
186
+ else if (dispatchAction === 'run_infra_repair') {
187
+ score = 0.4;
188
+ signals.push('bounded_infra_repair');
189
+ }
190
+ else if (dispatchAction === 'run_compile_repair') {
191
+ score = 0.4;
192
+ signals.push('bounded_compile_repair');
193
+ }
194
+ else if (dispatchAction === 'run_release_repair') {
195
+ score = 0.3;
196
+ signals.push('bounded_release_repair');
197
+ }
198
+ else if (dispatchAction === 'run_journey_contract_repair' || dispatchAction === 'run_business_assertion_repair') {
199
+ score = 0.25;
200
+ signals.push('bounded_workflow_or_proof_repair');
201
+ }
202
+ else if (dispatchAction === 'run_targeted_product_repair') {
203
+ score = 0.15;
204
+ signals.push('targeted_product_repair');
205
+ }
206
+ if (evidenceStrength === 'proof') {
207
+ score += 0.3;
208
+ signals.push('proof_evidence');
209
+ }
210
+ else if (materialEvidence) {
211
+ score += 0.2;
212
+ signals.push('material_evidence');
213
+ }
214
+ else if (newEvidence) {
215
+ score += 0.1;
216
+ signals.push('new_evidence');
217
+ }
218
+ else if (evidenceStrength === 'weak') {
219
+ score -= 0.15;
220
+ signals.push('weak_evidence');
221
+ }
222
+ else if (!isCheapEvidenceAutonomyAction(dispatchAction)) {
223
+ score -= 0.25;
224
+ signals.push('no_material_evidence');
225
+ }
226
+ if ((failureClass === 'infra' || /infra/i.test(recoveryClass)) && dispatchAction === 'run_infra_repair') {
227
+ score += 0.15;
228
+ signals.push('failure_matches_infra_repair');
229
+ }
230
+ if ((failureClass === 'compile' || /compile/i.test(recoveryClass)) && dispatchAction === 'run_compile_repair') {
231
+ score += 0.15;
232
+ signals.push('failure_matches_compile_repair');
233
+ }
234
+ if (/release|publish|deploy/i.test("".concat(failureClass, " ").concat(recoveryClass)) && dispatchAction === 'run_release_repair') {
235
+ score += 0.1;
236
+ signals.push('failure_matches_release_repair');
237
+ }
238
+ if (projectedActionCostUsd >= 5) {
239
+ score -= 0.3;
240
+ signals.push('high_projected_cost');
241
+ }
242
+ else if (projectedActionCostUsd >= 2) {
243
+ score -= 0.18;
244
+ signals.push('medium_projected_cost');
245
+ }
246
+ else if (projectedActionCostUsd >= 1) {
247
+ score -= 0.08;
248
+ signals.push('low_projected_cost');
249
+ }
250
+ if (budgetHardUsd > 0 && projectedActionCostUsd > budgetHardUsd * 0.5) {
251
+ score -= 0.2;
252
+ signals.push('large_fraction_of_remaining_budget');
253
+ }
254
+ if (input.sameEvidenceAlreadyAttempted === true) {
255
+ score -= 0.35;
256
+ signals.push('same_evidence_already_attempted');
257
+ }
258
+ try {
259
+ for (var evidenceSignals_1 = __values(evidenceSignals), evidenceSignals_1_1 = evidenceSignals_1.next(); !evidenceSignals_1_1.done; evidenceSignals_1_1 = evidenceSignals_1.next()) {
260
+ var signal = evidenceSignals_1_1.value;
261
+ if (/passing_outcome|business|proof|diagnosis|compile|infra|release|artifact|fingerprint_changed|evidence_hash_changed/i.test(signal)) {
262
+ score += 0.03;
263
+ signals.push("evidence_signal:".concat(signal));
264
+ }
265
+ }
266
+ }
267
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
268
+ finally {
269
+ try {
270
+ if (evidenceSignals_1_1 && !evidenceSignals_1_1.done && (_a = evidenceSignals_1.return)) _a.call(evidenceSignals_1);
271
+ }
272
+ finally { if (e_2) throw e_2.error; }
273
+ }
274
+ var rounded = Number(clampNumber(score, -1, 1).toFixed(2));
275
+ var minScore = 0;
276
+ return {
277
+ score: rounded,
278
+ minScore: minScore,
279
+ positive: rounded >= minScore,
280
+ source: 'estimated',
281
+ confidence: evidenceStrength === 'proof' || materialEvidence ? 'medium' : 'low',
282
+ reason: rounded >= minScore
283
+ ? 'estimated_retry_value_is_non_negative'
284
+ : 'estimated_retry_value_is_negative',
285
+ signals: Array.from(new Set(signals)).slice(0, 16)
286
+ };
287
+ }
288
+ function decideResolveIOAIManagerAutonomyPolicy(input) {
289
+ var _a;
290
+ if (input === void 0) { input = {}; }
291
+ var mode = normalizeAutonomyMode(input.mode);
292
+ var currentSpendUsd = nonNegativeMoney(input.currentSpendUsd);
293
+ var projectedActionCostUsd = nonNegativeMoney(input.projectedActionCostUsd);
294
+ var projectedSpendUsd = currentSpendUsd + projectedActionCostUsd;
295
+ var budgetSoftUsd = nonNegativeMoney(input.budgetSoftUsd);
296
+ var budgetHardUsd = nonNegativeMoney(input.budgetHardUsd);
297
+ var softBudgetExceeded = budgetSoftUsd > 0 && projectedSpendUsd >= budgetSoftUsd;
298
+ var hardBudgetExceeded = budgetHardUsd > 0 && projectedSpendUsd > budgetHardUsd;
299
+ var dispatchAction = cleanText(input.dispatchAction, 120);
300
+ var evidenceStrength = normalizeManagerEvidenceStrength(input.evidenceStrength);
301
+ var evidenceSignals = cleanList(input.evidenceSignals, 12, 120);
302
+ var materialEvidence = input.materialEvidence === true || evidenceStrength === 'material' || evidenceStrength === 'proof';
303
+ var newEvidence = input.newEvidence === true;
304
+ var evidenceBacked = materialEvidence || newEvidence || evidenceSignals.some(function (signal) { return /material|proof|business|compile|infra|release|diagnosis|journey|workflow|artifact|hash_changed|fingerprint_changed/i.test(signal); });
305
+ var cheapEvidenceAction = isCheapEvidenceAutonomyAction(dispatchAction);
306
+ var expectedValueEstimate = estimateResolveIOAIManagerRetryExpectedValue({
307
+ dispatchAction: dispatchAction,
308
+ projectedActionCostUsd: projectedActionCostUsd,
309
+ currentSpendUsd: currentSpendUsd,
310
+ budgetHardUsd: budgetHardUsd,
311
+ evidenceStrength: evidenceStrength,
312
+ materialEvidence: materialEvidence,
313
+ newEvidence: newEvidence,
314
+ evidenceSignals: evidenceSignals,
315
+ sameEvidenceAlreadyAttempted: input.sameEvidenceAlreadyAttempted === true
316
+ });
317
+ var providedExpectedValue = finiteNumber(input.expectedValueScore);
318
+ var expectedValueKnown = providedExpectedValue !== undefined;
319
+ var expectedValueScore = expectedValueKnown ? providedExpectedValue : expectedValueEstimate.score;
320
+ var minExpectedValue = (_a = finiteNumber(input.minExpectedValueScore)) !== null && _a !== void 0 ? _a : expectedValueEstimate.minScore;
321
+ var expectedValuePositive = expectedValueScore >= minExpectedValue;
322
+ var expectedValueSource = expectedValueKnown ? 'provided' : 'estimated';
323
+ var requiredEvidence = __spreadArray(__spreadArray(__spreadArray(__spreadArray([
324
+ 'mode',
325
+ 'projectedActionCostUsd'
326
+ ], __read((budgetHardUsd > 0 ? ['budgetHardUsd'] : [])), false), __read((budgetSoftUsd > 0 ? ['budgetSoftUsd'] : [])), false), __read((dispatchAction ? ['dispatchAction'] : [])), false), __read((cheapEvidenceAction ? [] : ['materialEvidence or newEvidence', 'expectedValueScore when available'])), false);
327
+ var forbiddenActions = [];
328
+ var canAutoDispatch = false;
329
+ var canManualDispatch = true;
330
+ var blocked = false;
331
+ var requiresHumanApproval = true;
332
+ var reason = '';
333
+ var recommendedControl = mode;
334
+ if (mode === 'monitor_only') {
335
+ canManualDispatch = false;
336
+ reason = 'monitor_only_blocks_runner_dispatch';
337
+ forbiddenActions.push('Do not run recovery, repair, QA, publish, deploy, or customer reply actions while in Monitor Only mode.');
338
+ }
339
+ else if (mode === 'manual_only') {
340
+ reason = 'manual_only_requires_operator_dispatch';
341
+ forbiddenActions.push('Do not auto-dispatch manager recovery actions in Manual Only mode.');
342
+ }
343
+ else if (hardBudgetExceeded) {
344
+ blocked = true;
345
+ canAutoDispatch = false;
346
+ canManualDispatch = input.operatorApproved === true;
347
+ reason = 'auto_retry_budget_hard_cap_would_be_exceeded';
348
+ recommendedControl = 'increase_budget_or_manual';
349
+ forbiddenActions.push('Do not auto-dispatch because projected spend exceeds the hard budget.');
350
+ }
351
+ else if (!cheapEvidenceAction && !evidenceBacked) {
352
+ canAutoDispatch = false;
353
+ requiresHumanApproval = true;
354
+ reason = 'auto_retry_requires_material_evidence';
355
+ forbiddenActions.push('Do not auto-dispatch repair work until a deterministic artifact, changed blocker fingerprint, or material proof is recorded.');
356
+ }
357
+ else if (!cheapEvidenceAction && !expectedValuePositive) {
358
+ canAutoDispatch = false;
359
+ requiresHumanApproval = true;
360
+ reason = 'auto_retry_expected_value_not_positive';
361
+ forbiddenActions.push('Do not auto-dispatch repair work when the expected value score is below the configured minimum.');
362
+ }
363
+ else {
364
+ canAutoDispatch = true;
365
+ requiresHumanApproval = softBudgetExceeded;
366
+ reason = softBudgetExceeded
367
+ ? 'auto_retry_soft_budget_warning_requires_review'
368
+ : 'auto_retry_within_budget_allows_auto_dispatch';
369
+ if (softBudgetExceeded) {
370
+ forbiddenActions.push('Do not escalate to a more expensive model or broader repair without operator review after soft budget warning.');
371
+ }
372
+ }
373
+ return {
374
+ mode: mode,
375
+ canAutoDispatch: canAutoDispatch,
376
+ canManualDispatch: canManualDispatch,
377
+ blocked: blocked,
378
+ requiresHumanApproval: requiresHumanApproval,
379
+ reason: reason,
380
+ currentSpendUsd: currentSpendUsd,
381
+ projectedActionCostUsd: projectedActionCostUsd,
382
+ projectedSpendUsd: projectedSpendUsd,
383
+ budgetSoftUsd: budgetSoftUsd,
384
+ budgetHardUsd: budgetHardUsd,
385
+ softBudgetExceeded: softBudgetExceeded,
386
+ hardBudgetExceeded: hardBudgetExceeded,
387
+ dispatchAction: dispatchAction,
388
+ expectedValueScore: expectedValueScore,
389
+ minExpectedValueScore: minExpectedValue,
390
+ expectedValueKnown: expectedValueKnown,
391
+ expectedValueSource: expectedValueSource,
392
+ expectedValuePositive: expectedValuePositive,
393
+ evidenceStrength: evidenceStrength,
394
+ materialEvidence: materialEvidence,
395
+ newEvidence: newEvidence,
396
+ evidenceBacked: evidenceBacked,
397
+ evidenceSignals: evidenceSignals,
398
+ recommendedControl: recommendedControl,
399
+ forbiddenActions: forbiddenActions,
400
+ requiredEvidence: requiredEvidence
401
+ };
402
+ }
403
+ function cleanDateString(value) {
404
+ var date = value instanceof Date ? value : new Date(value || Date.now());
405
+ return Number.isNaN(date.getTime()) ? new Date().toISOString() : date.toISOString();
406
+ }
117
407
  function normalizeHotfixChannel(value) {
118
408
  var normalized = cleanText(value, 120).toLowerCase().replace(/[\s-]+/g, '_');
119
409
  return HOTFIX_CHANNELS.has(normalized) ? normalized : '';
@@ -185,6 +475,7 @@ function normalizeResolveIOAIManagerHotfixEvidence(value, policy) {
185
475
  sourceCommitSha: cleanText(source.sourceCommitSha || source.source_commit_sha || source.gitCommitSha || source.git_commit_sha || source.commitSha || source.commit_sha, 120),
186
476
  githubCommitUrl: cleanText(source.githubCommitUrl || source.github_commit_url || source.gitCommitUrl || source.git_commit_url || source.commitUrl || source.commit_url, 500),
187
477
  gitCommitStatus: cleanText(source.gitCommitStatus || source.git_commit_status || source.githubCommitStatus || source.github_commit_status, 160),
478
+ gitPushStatus: cleanText(source.gitPushStatus || source.git_push_status || source.githubPushStatus || source.github_push_status || source.githubCommitReachableStatus || source.github_commit_reachable_status, 160),
188
479
  committedAt: source.committedAt || source.committed_at,
189
480
  forceDeployReason: cleanText(source.forceDeployReason || source.force_deploy_reason, 1000),
190
481
  hotfixCannotResolveReason: cleanText(source.hotfixCannotResolveReason || source.hotfix_cannot_resolve_reason, 1000),
@@ -204,8 +495,96 @@ function pushMissing(blockers, condition, message) {
204
495
  function hotfixRequiresGithubCommit(channel) {
205
496
  return /^(backend_js|static_ui|config|seed_data|release_artifact|new_artifact_deploy|artifact_build)$/.test(channel);
206
497
  }
207
- function hotfixHasGithubCommitProof(value) {
208
- return !!value.sourceCommitSha && (!!value.githubCommitUrl || hotfixStatusPassed(value.gitCommitStatus));
498
+ function extractGithubCommitSha(value) {
499
+ var _a;
500
+ var match = cleanText(value, 500).match(/^https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/commit\/([a-f0-9]{40})(?:$|[?#/])/i);
501
+ return ((_a = match === null || match === void 0 ? void 0 : match[1]) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
502
+ }
503
+ function isFullGitCommitSha(value) {
504
+ return /^[a-f0-9]{40}$/i.test(cleanText(value, 120));
505
+ }
506
+ function isStrongRemoteChecksum(value) {
507
+ return /^[a-f0-9]{12,128}$/i.test(cleanText(value, 160));
508
+ }
509
+ function githubCommitProofBlockers(value, channel) {
510
+ var blockers = [];
511
+ var sourceCommitSha = cleanText(value.sourceCommitSha, 120);
512
+ var githubCommitUrl = cleanText(value.githubCommitUrl, 500);
513
+ var gitCommitStatus = cleanText(value.gitCommitStatus, 160);
514
+ var remoteCommitProofStatus = cleanText(value.gitPushStatus || value.gitCommitStatus, 160);
515
+ var urlCommitSha = extractGithubCommitSha(githubCommitUrl);
516
+ if (!sourceCommitSha || !githubCommitUrl) {
517
+ blockers.push("".concat(channel, " hotfix requires sourceCommitSha, githubCommitUrl, and passed gitPushStatus so live hotfixes are backed by a GitHub commit pushed before continuation."));
518
+ return blockers;
519
+ }
520
+ if (!isFullGitCommitSha(sourceCommitSha)) {
521
+ blockers.push("".concat(channel, " hotfix sourceCommitSha must be a full 40-character git SHA."));
522
+ }
523
+ if (!urlCommitSha) {
524
+ blockers.push("".concat(channel, " hotfix githubCommitUrl must be a GitHub commit URL ending in a full 40-character git SHA."));
525
+ }
526
+ else if (isFullGitCommitSha(sourceCommitSha) && urlCommitSha !== sourceCommitSha.toLowerCase()) {
527
+ blockers.push("".concat(channel, " hotfix githubCommitUrl commit SHA must match sourceCommitSha."));
528
+ }
529
+ if (!remoteCommitProofStatus) {
530
+ blockers.push("".concat(channel, " hotfix requires passed gitPushStatus or gitCommitStatus so the manager knows the hotfix commit is present on GitHub before continuation."));
531
+ }
532
+ else if (!hotfixStatusPassed(remoteCommitProofStatus)) {
533
+ blockers.push("".concat(channel, " hotfix gitPushStatus or gitCommitStatus must be passed before continuation."));
534
+ }
535
+ if (gitCommitStatus && gitCommitStatus !== remoteCommitProofStatus && !hotfixStatusPassed(gitCommitStatus)) {
536
+ blockers.push("".concat(channel, " hotfix gitCommitStatus must be passed when provided."));
537
+ }
538
+ return blockers;
539
+ }
540
+ function evaluateResolveIOAIManagerHotfixGitProof(value, channelHint) {
541
+ if (channelHint === void 0) { channelHint = ''; }
542
+ var normalized = normalizeResolveIOAIManagerHotfixEvidence(value);
543
+ var source = (normalized || cleanObject(value));
544
+ var channel = (channelHint || (normalized === null || normalized === void 0 ? void 0 : normalized.channel) || source.channel || '');
545
+ var required = hotfixRequiresGithubCommit(channel);
546
+ var sourceCommitSha = cleanText(source.sourceCommitSha || source.source_commit_sha || source.gitCommitSha || source.git_commit_sha || source.commitSha || source.commit_sha, 120);
547
+ var githubCommitUrl = cleanText(source.githubCommitUrl || source.github_commit_url || source.gitCommitUrl || source.git_commit_url || source.commitUrl || source.commit_url, 500);
548
+ var githubCommitSha = extractGithubCommitSha(githubCommitUrl);
549
+ var gitCommitStatus = cleanText(source.gitCommitStatus || source.git_commit_status || source.githubCommitStatus || source.github_commit_status, 160);
550
+ var gitPushStatus = cleanText(source.gitPushStatus || source.git_push_status || source.githubPushStatus || source.github_push_status || source.githubCommitReachableStatus || source.github_commit_reachable_status || gitCommitStatus, 160);
551
+ var blockers = required
552
+ ? githubCommitProofBlockers({
553
+ channel: channel,
554
+ target: (normalized === null || normalized === void 0 ? void 0 : normalized.target) || {},
555
+ sourceCommitSha: sourceCommitSha,
556
+ githubCommitUrl: githubCommitUrl,
557
+ gitCommitStatus: gitCommitStatus,
558
+ gitPushStatus: gitPushStatus
559
+ }, channel)
560
+ : [];
561
+ var status = !required
562
+ ? 'not_required'
563
+ : (!sourceCommitSha || !githubCommitUrl || !gitPushStatus)
564
+ ? 'missing'
565
+ : blockers.length
566
+ ? 'invalid'
567
+ : 'passed';
568
+ var passed = !required || status === 'passed';
569
+ return {
570
+ required: required,
571
+ status: status,
572
+ passed: passed,
573
+ managerMustCommitBeforeHotfix: required && !passed,
574
+ channel: channel,
575
+ sourceCommitSha: sourceCommitSha,
576
+ githubCommitUrl: githubCommitUrl,
577
+ githubCommitSha: githubCommitSha,
578
+ gitCommitStatus: gitCommitStatus,
579
+ gitPushStatus: gitPushStatus,
580
+ blockers: blockers,
581
+ nextCommands: required && !passed
582
+ ? ['commit_and_push_hotfix_to_github', 'verify_github_commit_url_and_push_status', 'record_hotfix_evidence']
583
+ : [],
584
+ requiredEvidence: required
585
+ ? ['full 40-character sourceCommitSha', 'matching GitHub commit URL', 'passed gitPushStatus or gitCommitStatus']
586
+ : []
587
+ };
209
588
  }
210
589
  function validateResolveIOAIManagerHotfixEvidence(value, options) {
211
590
  var _a, _b, _c, _d;
@@ -224,6 +603,7 @@ function validateResolveIOAIManagerHotfixEvidence(value, options) {
224
603
  hotfixSatisfied: false,
225
604
  requiredEvidence: ((_b = (_a = policy === null || policy === void 0 ? void 0 : policy.hotfixPlan) === null || _a === void 0 ? void 0 : _a.steps) === null || _b === void 0 ? void 0 : _b.flatMap(function (step) { return step.requiredEvidence; })) || [],
226
605
  successEvidence: ((_d = (_c = policy === null || policy === void 0 ? void 0 : policy.hotfixPlan) === null || _c === void 0 ? void 0 : _c.steps) === null || _d === void 0 ? void 0 : _d.flatMap(function (step) { return step.successEvidence; })) || [],
606
+ githubCommitGuard: evaluateResolveIOAIManagerHotfixGitProof(value),
227
607
  policy: policy,
228
608
  nextAction: 'record_hotfix_evidence'
229
609
  };
@@ -237,20 +617,24 @@ function validateResolveIOAIManagerHotfixEvidence(value, options) {
237
617
  var successEvidence = (step === null || step === void 0 ? void 0 : step.successEvidence) || [];
238
618
  var policyAllowsFullDeploy = (policy === null || policy === void 0 ? void 0 : policy.fullDeployAllowed) === true;
239
619
  var policyBlocksDuplicate = (policy === null || policy === void 0 ? void 0 : policy.duplicateDeployBlocked) === true || (policy === null || policy === void 0 ? void 0 : policy.duplicatePublishBlocked) === true;
620
+ var githubCommitGuard = evaluateResolveIOAIManagerHotfixGitProof(normalized, channel);
240
621
  if (normalized.fullDeployRequested && !policyAllowsFullDeploy && channel !== 'force_deploy_review' && channel !== 'new_artifact_deploy') {
241
622
  blockers.push('Full deploy requested but hotfix-first policy does not allow a full deploy for this release state.');
242
623
  }
243
624
  if (normalized.fullDeployRequested && policyBlocksDuplicate && !normalized.forceDeployReason && channel !== 'force_deploy_review') {
244
625
  blockers.push('Duplicate deploy/publish fingerprint requires force deploy/publish evidence before any full deploy.');
245
626
  }
246
- if (hotfixRequiresGithubCommit(channel)) {
247
- pushMissing(blockers, hotfixHasGithubCommitProof(normalized), "".concat(channel, " hotfix requires sourceCommitSha plus githubCommitUrl or passed gitCommitStatus so live hotfixes are not lost."));
627
+ if (githubCommitGuard.required) {
628
+ blockers.push.apply(blockers, __spreadArray([], __read(githubCommitGuard.blockers), false));
248
629
  }
249
630
  if (channel === 'backend_js') {
250
631
  pushMissing(blockers, !!normalized.compiledArtifactPath, 'Backend JS hotfix requires compiledArtifactPath.');
251
632
  pushMissing(blockers, !!target.host, 'Backend JS hotfix requires target.host.');
252
633
  pushMissing(blockers, !!target.path, 'Backend JS hotfix requires target.path.');
253
634
  pushMissing(blockers, !!(normalized.remoteChecksumAfter || normalized.remoteChecksum), 'Backend JS hotfix requires remote checksum after replacement.');
635
+ if ((normalized.remoteChecksumAfter || normalized.remoteChecksum) && !isStrongRemoteChecksum(normalized.remoteChecksumAfter || normalized.remoteChecksum || '')) {
636
+ blockers.push('Backend JS hotfix remote checksum after replacement must be a strong hex checksum, not a label or placeholder.');
637
+ }
254
638
  pushMissing(blockers, !!(normalized.restartEvidence || normalized.serviceRestartEvidence), 'Backend JS hotfix requires restart evidence.');
255
639
  pushMissing(blockers, hotfixStatusPassed(normalized.healthCheckStatus), 'Backend JS hotfix requires passed healthCheckStatus.');
256
640
  pushMissing(blockers, hotfixStatusPassed(normalized.selfTestStatus), 'Backend JS hotfix requires passed selfTestStatus.');
@@ -342,21 +726,228 @@ function validateResolveIOAIManagerHotfixEvidence(value, options) {
342
726
  requiredEvidence: requiredEvidence,
343
727
  successEvidence: successEvidence,
344
728
  normalized: normalized,
729
+ githubCommitGuard: githubCommitGuard,
345
730
  policy: policy,
346
731
  nextAction: nextAction
347
732
  };
348
733
  }
349
- function decideResolveIOAIManagerHotfixContinuation(input) {
734
+ function mergeHotfixEvidenceRecordInput(input) {
735
+ var e_3, _a;
736
+ var merged = __assign({}, cleanObject(input.evidence));
737
+ var directFields = [
738
+ 'channel',
739
+ 'status',
740
+ 'target',
741
+ 'compiledArtifactPath',
742
+ 'builtDistPath',
743
+ 'remoteChecksumBefore',
744
+ 'remoteChecksumAfter',
745
+ 'remoteChecksum',
746
+ 'restartEvidence',
747
+ 'healthCheckStatus',
748
+ 'selfTestStatus',
749
+ 'releaseGateStatus',
750
+ 's3UploadResult',
751
+ 'cloudfrontInvalidationId',
752
+ 'publicProof',
753
+ 'configChangeEvidence',
754
+ 'seedDataEvidence',
755
+ 'cacheInvalidationEvidence',
756
+ 'serviceRestartEvidence',
757
+ 'releaseArtifactFingerprint',
758
+ 'lastReleaseArtifactFingerprint',
759
+ 'sourceCommitSha',
760
+ 'githubCommitUrl',
761
+ 'gitCommitStatus',
762
+ 'gitPushStatus',
763
+ 'committedAt',
764
+ 'forceDeployReason',
765
+ 'hotfixCannotResolveReason',
766
+ 'fullDeployRequested',
767
+ 'recordedAt'
768
+ ];
769
+ try {
770
+ for (var directFields_1 = __values(directFields), directFields_1_1 = directFields_1.next(); !directFields_1_1.done; directFields_1_1 = directFields_1.next()) {
771
+ var field = directFields_1_1.value;
772
+ var value = input[field];
773
+ if (value !== undefined && value !== null && value !== '') {
774
+ merged[field] = value;
775
+ }
776
+ }
777
+ }
778
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
779
+ finally {
780
+ try {
781
+ if (directFields_1_1 && !directFields_1_1.done && (_a = directFields_1.return)) _a.call(directFields_1);
782
+ }
783
+ finally { if (e_3) throw e_3.error; }
784
+ }
785
+ return merged;
786
+ }
787
+ function resolveHotfixEvidenceRequiredFields(channel) {
788
+ var fields = ['channel'];
789
+ if (hotfixRequiresGithubCommit(channel)) {
790
+ fields.push('sourceCommitSha', 'githubCommitUrl', 'gitPushStatus');
791
+ }
792
+ if (channel === 'backend_js') {
793
+ fields.push('compiledArtifactPath', 'target.host', 'target.path', 'remoteChecksumAfter', 'restartEvidence', 'healthCheckStatus', 'selfTestStatus');
794
+ }
795
+ else if (channel === 'static_ui') {
796
+ fields.push('builtDistPath', 'target.bucket', 'target.distributionId', 's3UploadResult', 'cloudfrontInvalidationId', 'publicProof');
797
+ }
798
+ else if (channel === 'config') {
799
+ fields.push('target.configKey', 'configChangeEvidence', 'releaseGateStatus');
800
+ }
801
+ else if (channel === 'seed_data') {
802
+ fields.push('target.seedKey', 'seedDataEvidence', 'releaseGateStatus');
803
+ }
804
+ else if (channel === 'cache_invalidation') {
805
+ fields.push('target.cacheKey', 'cacheInvalidationEvidence', 'releaseGateStatus_or_healthCheckStatus');
806
+ }
807
+ else if (channel === 'service_restart') {
808
+ fields.push('target.processName', 'serviceRestartEvidence', 'healthCheckStatus', 'selfTestStatus');
809
+ }
810
+ else if (channel === 'release_artifact') {
811
+ fields.push('releaseArtifactFingerprint', 'releaseGateStatus');
812
+ }
813
+ else if (channel === 'new_artifact_deploy') {
814
+ fields.push('releaseArtifactFingerprint', 'lastReleaseArtifactFingerprint', 'releaseGateStatus');
815
+ }
816
+ else if (channel === 'artifact_build') {
817
+ fields.push('releaseArtifactFingerprint');
818
+ }
819
+ else if (channel === 'force_deploy_review') {
820
+ fields.push('forceDeployReason', 'hotfixCannotResolveReason');
821
+ }
822
+ return Array.from(new Set(fields));
823
+ }
824
+ function hotfixEvidenceFieldPresent(evidence, field) {
825
+ if (!evidence) {
826
+ return false;
827
+ }
828
+ var target = evidence.target || {};
829
+ switch (field) {
830
+ case 'channel':
831
+ return !!evidence.channel;
832
+ case 'sourceCommitSha':
833
+ return isFullGitCommitSha(evidence.sourceCommitSha || '');
834
+ case 'githubCommitUrl':
835
+ return !!extractGithubCommitSha(evidence.githubCommitUrl || '');
836
+ case 'gitPushStatus':
837
+ return hotfixStatusPassed(evidence.gitPushStatus) || hotfixStatusPassed(evidence.gitCommitStatus);
838
+ case 'compiledArtifactPath':
839
+ return !!cleanText(evidence.compiledArtifactPath, 500);
840
+ case 'builtDistPath':
841
+ return !!cleanText(evidence.builtDistPath, 500);
842
+ case 'remoteChecksumAfter':
843
+ return !!cleanText(evidence.remoteChecksumAfter || evidence.remoteChecksum, 160);
844
+ case 'restartEvidence':
845
+ return !!cleanText(evidence.restartEvidence || evidence.serviceRestartEvidence, 1000);
846
+ case 'serviceRestartEvidence':
847
+ return !!cleanText(evidence.serviceRestartEvidence || evidence.restartEvidence, 1000);
848
+ case 'healthCheckStatus':
849
+ return hotfixStatusPassed(evidence.healthCheckStatus);
850
+ case 'selfTestStatus':
851
+ return hotfixStatusPassed(evidence.selfTestStatus);
852
+ case 'releaseGateStatus':
853
+ return hotfixStatusPassed(evidence.releaseGateStatus);
854
+ case 'releaseGateStatus_or_healthCheckStatus':
855
+ return hotfixStatusPassed(evidence.releaseGateStatus) || hotfixStatusPassed(evidence.healthCheckStatus);
856
+ case 's3UploadResult':
857
+ return !!cleanText(evidence.s3UploadResult, 1000);
858
+ case 'cloudfrontInvalidationId':
859
+ return !!cleanText(evidence.cloudfrontInvalidationId, 240);
860
+ case 'publicProof':
861
+ return !!cleanText(evidence.publicProof, 1000);
862
+ case 'configChangeEvidence':
863
+ return !!cleanText(evidence.configChangeEvidence, 1000);
864
+ case 'seedDataEvidence':
865
+ return !!cleanText(evidence.seedDataEvidence, 1000);
866
+ case 'cacheInvalidationEvidence':
867
+ return !!cleanText(evidence.cacheInvalidationEvidence, 1000);
868
+ case 'releaseArtifactFingerprint':
869
+ return !!cleanText(evidence.releaseArtifactFingerprint, 240);
870
+ case 'lastReleaseArtifactFingerprint':
871
+ return !!cleanText(evidence.lastReleaseArtifactFingerprint, 240);
872
+ case 'forceDeployReason':
873
+ return !!cleanText(evidence.forceDeployReason, 1000);
874
+ case 'hotfixCannotResolveReason':
875
+ return !!cleanText(evidence.hotfixCannotResolveReason, 1000);
876
+ case 'target.host':
877
+ return !!cleanText(target.host, 200);
878
+ case 'target.path':
879
+ return !!cleanText(target.path, 500);
880
+ case 'target.bucket':
881
+ return !!cleanText(target.bucket, 200);
882
+ case 'target.distributionId':
883
+ return !!cleanText(target.distributionId, 200);
884
+ case 'target.configKey':
885
+ return !!cleanText(target.configKey, 200);
886
+ case 'target.seedKey':
887
+ return !!cleanText(target.seedKey, 200);
888
+ case 'target.cacheKey':
889
+ return !!cleanText(target.cacheKey, 200);
890
+ case 'target.processName':
891
+ return !!cleanText(target.processName, 200);
892
+ default:
893
+ return false;
894
+ }
895
+ }
896
+ function buildResolveIOAIManagerHotfixEvidenceRecord(input) {
350
897
  var _a, _b;
351
898
  if (input === void 0) { input = {}; }
899
+ var merged = mergeHotfixEvidenceRecordInput(input);
900
+ var normalized = normalizeResolveIOAIManagerHotfixEvidence(merged, input.policy);
901
+ var validation = validateResolveIOAIManagerHotfixEvidence(merged, { policy: input.policy });
902
+ var channel = validation.channel || (normalized === null || normalized === void 0 ? void 0 : normalized.channel) || ((_b = (_a = input.policy) === null || _a === void 0 ? void 0 : _a.hotfixPlan) === null || _b === void 0 ? void 0 : _b.recommendedChannel) || '';
903
+ var requiredFields = resolveHotfixEvidenceRequiredFields(channel);
904
+ var missingFields = requiredFields.filter(function (field) { return !hotfixEvidenceFieldPresent(normalized, field); });
905
+ var recordedAt = cleanDateString(input.now || (normalized === null || normalized === void 0 ? void 0 : normalized.recordedAt) || new Date());
906
+ var githubCommitGuard = validation.githubCommitGuard || evaluateResolveIOAIManagerHotfixGitProof(normalized || merged, channel);
907
+ return {
908
+ recordId: cleanText(input.recordId, 160) || "hotfix-".concat(fingerprintResolveIOAIManagerBlocker("".concat(channel, ":").concat(githubCommitGuard.sourceCommitSha, ":").concat(recordedAt))),
909
+ recordedAt: recordedAt,
910
+ recordedBy: cleanText(input.recordedBy || 'manager', 160),
911
+ source: cleanText(input.source || 'unknown', 80),
912
+ reason: cleanText(input.reason, 1000),
913
+ channel: channel,
914
+ status: validation.status,
915
+ nextAction: validation.nextAction,
916
+ valid: validation.valid,
917
+ hotfixSatisfied: validation.hotfixSatisfied,
918
+ fullDeployAllowed: validation.fullDeployAllowed,
919
+ fullDeployBlocked: validation.fullDeployBlocked,
920
+ requiredFields: requiredFields,
921
+ missingFields: missingFields,
922
+ evidence: normalized,
923
+ validation: validation,
924
+ sourceCommitSha: githubCommitGuard.sourceCommitSha,
925
+ githubCommitUrl: githubCommitGuard.githubCommitUrl,
926
+ gitPushStatus: githubCommitGuard.gitPushStatus,
927
+ githubCommitRequired: githubCommitGuard.required,
928
+ githubCommitProofPassed: githubCommitGuard.passed,
929
+ commitProofStatus: githubCommitGuard.status,
930
+ managerMustCommitBeforeHotfix: githubCommitGuard.managerMustCommitBeforeHotfix,
931
+ githubCommitGuard: githubCommitGuard,
932
+ readyForReleaseGate: validation.valid === true && validation.nextAction === 'rerun_release_gate',
933
+ readyForContinuation: validation.valid === true && validation.hotfixSatisfied === true && hotfixStatusPassed(normalized === null || normalized === void 0 ? void 0 : normalized.releaseGateStatus)
934
+ };
935
+ }
936
+ function decideResolveIOAIManagerHotfixContinuation(input) {
937
+ var e_4, _a;
938
+ var _b, _c;
939
+ if (input === void 0) { input = {}; }
352
940
  var validation = validateResolveIOAIManagerHotfixEvidence(input.evidence, { policy: input.policy });
353
941
  var failureClass = cleanText(input.failureClass, 120) || 'release';
354
- var blockerText = cleanText(input.blocker || validation.blockers.join('; ') || ((_a = validation.normalized) === null || _a === void 0 ? void 0 : _a.hotfixCannotResolveReason), 1000);
942
+ var blockerText = cleanText(input.blocker || validation.blockers.join('; ') || ((_b = validation.normalized) === null || _b === void 0 ? void 0 : _b.hotfixCannotResolveReason), 1000);
355
943
  var blockerFingerprint = fingerprintResolveIOAIManagerBlocker(blockerText || "".concat(validation.channel, ":").concat(validation.status, ":").concat(validation.nextAction));
356
944
  var baseBlockers = __spreadArray([], __read(validation.blockers), false);
945
+ var githubCommitGuard = validation.githubCommitGuard || evaluateResolveIOAIManagerHotfixGitProof(input.evidence, validation.channel);
946
+ var needsGithubCommitProof = githubCommitGuard.managerMustCommitBeforeHotfix
947
+ || validation.blockers.some(function (blocker) { return /sourceCommitSha|githubCommitUrl|gitPushStatus|gitCommitStatus|GitHub commit|pushed/i.test(blocker); });
357
948
  var repeatedFailure = input.repeatedFailure === true;
358
949
  var releaseGatePassed = input.releaseGatePassed === true
359
- || hotfixStatusPassed((_b = validation.normalized) === null || _b === void 0 ? void 0 : _b.releaseGateStatus);
950
+ || hotfixStatusPassed((_c = validation.normalized) === null || _c === void 0 ? void 0 : _c.releaseGateStatus);
360
951
  var action = validation.nextAction;
361
952
  var canContinueRun = false;
362
953
  var canRunFullDeploy = validation.fullDeployAllowed;
@@ -364,13 +955,38 @@ function decideResolveIOAIManagerHotfixContinuation(input) {
364
955
  var shouldPark = false;
365
956
  var reason = '';
366
957
  var nextCommands = [];
367
- if (!validation.valid || validation.status === 'missing' || validation.status === 'incomplete') {
958
+ if (githubCommitGuard.managerMustCommitBeforeHotfix) {
959
+ action = 'record_hotfix_evidence';
960
+ reason = githubCommitGuard.blockers.length
961
+ ? "Manager hotfix cannot continue until the hotfix is committed and pushed: ".concat(githubCommitGuard.blockers.join('; '))
962
+ : 'Manager hotfix cannot continue until sourceCommitSha, githubCommitUrl, and passed gitPushStatus prove the hotfix is on GitHub.';
963
+ nextCommands.push.apply(nextCommands, __spreadArray(__spreadArray([], __read(githubCommitGuard.nextCommands), false), ['rerun_hotfix_evidence_validator'], false));
964
+ try {
965
+ for (var _d = __values(githubCommitGuard.blockers), _e = _d.next(); !_e.done; _e = _d.next()) {
966
+ var blocker = _e.value;
967
+ if (!baseBlockers.includes(blocker)) {
968
+ baseBlockers.push(blocker);
969
+ }
970
+ }
971
+ }
972
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
973
+ finally {
974
+ try {
975
+ if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
976
+ }
977
+ finally { if (e_4) throw e_4.error; }
978
+ }
979
+ }
980
+ else if (!validation.valid || validation.status === 'missing' || validation.status === 'incomplete') {
368
981
  action = validation.nextAction === 'request_force_deploy_reason'
369
982
  ? 'request_force_deploy_reason'
370
983
  : 'record_hotfix_evidence';
371
984
  reason = validation.blockers.length
372
985
  ? "Hotfix evidence is not complete: ".concat(validation.blockers.join('; '))
373
986
  : 'Hotfix evidence is missing; record the hotfix target, checksum, restart, health, and self-test proof before continuing.';
987
+ if (needsGithubCommitProof) {
988
+ nextCommands.push('commit_and_push_hotfix_to_github', 'verify_github_commit_url_and_push_status');
989
+ }
374
990
  nextCommands.push('record_hotfix_evidence', 'rerun_hotfix_evidence_validator');
375
991
  }
376
992
  else if (validation.fullDeployAllowed) {
@@ -415,13 +1031,49 @@ function decideResolveIOAIManagerHotfixContinuation(input) {
415
1031
  warnings: validation.warnings,
416
1032
  requiredEvidence: validation.requiredEvidence,
417
1033
  successEvidence: validation.successEvidence,
418
- nextCommands: nextCommands,
1034
+ nextCommands: Array.from(new Set(nextCommands)),
419
1035
  failureClass: failureClass,
420
1036
  blockerFingerprint: blockerFingerprint,
1037
+ githubCommitGuard: githubCommitGuard,
421
1038
  validation: validation,
422
1039
  recordedAt: isoNow(input.now)
423
1040
  };
424
1041
  }
1042
+ function decideResolveIOAIManagerHotfixCommitGuard(input) {
1043
+ if (input === void 0) { input = {}; }
1044
+ var normalized = normalizeResolveIOAIManagerHotfixEvidence(input.evidence, input.policy);
1045
+ var validation = validateResolveIOAIManagerHotfixEvidence(input.evidence, { policy: input.policy });
1046
+ var githubCommitGuard = validation.githubCommitGuard || evaluateResolveIOAIManagerHotfixGitProof(input.evidence, validation.channel);
1047
+ var active = !!normalized || githubCommitGuard.required === true;
1048
+ var hotfixCommitBlockers = validation.blockers.filter(function (blocker) { return /sourceCommitSha|githubCommitUrl|gitPushStatus|gitCommitStatus|GitHub commit|pushed/i.test(blocker); });
1049
+ var blockers = Array.from(new Set(__spreadArray(__spreadArray([], __read((githubCommitGuard.blockers || [])), false), __read(hotfixCommitBlockers), false)));
1050
+ var blocked = active && (githubCommitGuard.managerMustCommitBeforeHotfix === true
1051
+ || (githubCommitGuard.required === true && githubCommitGuard.passed !== true)
1052
+ || hotfixCommitBlockers.length > 0);
1053
+ var nextCommands = blocked
1054
+ ? Array.from(new Set(__spreadArray(__spreadArray([], __read((githubCommitGuard.nextCommands || [])), false), [
1055
+ 'commit_and_push_hotfix_to_github',
1056
+ 'verify_github_commit_url_and_push_status',
1057
+ 'record_hotfix_evidence'
1058
+ ], false)))
1059
+ : [];
1060
+ return {
1061
+ active: active,
1062
+ blocked: blocked,
1063
+ reason: blocked
1064
+ ? (blockers.length
1065
+ ? "Hotfix continuation is blocked until GitHub commit proof is recorded: ".concat(blockers.join('; '))
1066
+ : 'Hotfix continuation is blocked until sourceCommitSha, githubCommitUrl, and passed gitPushStatus prove the hotfix is pushed to GitHub.')
1067
+ : (active ? 'Hotfix GitHub commit proof is recorded.' : 'No hotfix commit guard is active.'),
1068
+ nextAction: blocked ? 'record_hotfix_evidence' : 'continue',
1069
+ channel: validation.channel || githubCommitGuard.channel || '',
1070
+ blockers: blockers,
1071
+ nextCommands: nextCommands,
1072
+ requiredEvidence: githubCommitGuard.requiredEvidence,
1073
+ githubCommitGuard: githubCommitGuard,
1074
+ validation: validation
1075
+ };
1076
+ }
425
1077
  function releaseStatusIsBlocked(value) {
426
1078
  return /fail|error|blocked|missing|empty|not ready|not_ready|denied|invalid|timeout|stale/i.test(value);
427
1079
  }
@@ -563,17 +1215,17 @@ function buildHotfixFirstReleasePlan(input) {
563
1215
  steps: [
564
1216
  hotfixStep('static_ui_hotfix', 'Static UI hotfix', 'static_ui', {
565
1217
  safeToAutoRun: true,
566
- requiredEvidence: ['built dist path', 'target S3 bucket and CloudFront distribution', 'changed frontend bundle or asset list'],
567
- successEvidence: ['S3 upload result', 'CloudFront invalidation id', 'public bundle contains expected hotfix marker']
1218
+ requiredEvidence: ['sourceCommitSha, githubCommitUrl, and passed gitPushStatus', 'built dist path', 'target S3 bucket and CloudFront distribution', 'changed frontend bundle or asset list'],
1219
+ successEvidence: ['GitHub commit and push proof', 'S3 upload result', 'CloudFront invalidation id', 'public bundle contains expected hotfix marker']
568
1220
  }),
569
1221
  hotfixStep('backend_js_hotfix', 'Backend JS hotfix', 'backend_js', {
570
- requiredEvidence: ['compiled JS artifact path', 'target backend host', 'diff limited to runner/operator code'],
571
- successEvidence: ['remote file checksum', 'service restart or process reload evidence', 'self-test passes']
1222
+ requiredEvidence: ['sourceCommitSha, githubCommitUrl, and passed gitPushStatus', 'compiled JS artifact path', 'target backend host', 'diff limited to runner/operator code'],
1223
+ successEvidence: ['GitHub commit and push proof', 'remote file checksum', 'service restart or process reload evidence', 'self-test passes']
572
1224
  }),
573
1225
  hotfixStep('config_seed_cache_restart', 'Config, seed, cache, or restart repair', 'config', {
574
1226
  safeToAutoRun: true,
575
- requiredEvidence: ['exact config/seed/cache key or process name', 'why no product artifact changed'],
576
- successEvidence: ['release gate rerun result', 'operator console release snapshot refreshed']
1227
+ requiredEvidence: ['sourceCommitSha, githubCommitUrl, and passed gitPushStatus', 'exact config/seed/cache key or process name', 'why no product artifact changed'],
1228
+ successEvidence: ['GitHub commit and push proof', 'release gate rerun result', 'operator console release snapshot refreshed']
577
1229
  })
578
1230
  ],
579
1231
  acceptanceEvidence: commonAcceptance,
@@ -1030,6 +1682,48 @@ function recoveryActionAutoRunnable(mode, probe) {
1030
1682
  }
1031
1683
  return probe.steps.some(function (step) { return step.commandHint || step.kind === 'rerun_same_gate' || step.kind === 'release_status' || step.kind === 'diff_scope_check'; });
1032
1684
  }
1685
+ function recoveryActionCostCeilingUsd(mode) {
1686
+ var _a;
1687
+ var map = {
1688
+ advance: 0,
1689
+ collect_evidence: 0.25,
1690
+ read_only_diagnosis: 1,
1691
+ repair_infra: 0.5,
1692
+ repair_compile: 1.5,
1693
+ repair_journey_contract: 2,
1694
+ repair_business_assertion: 1.5,
1695
+ repair_release: 0.75,
1696
+ targeted_product_repair: 5,
1697
+ manual_review: 0,
1698
+ continue_gate: 0
1699
+ };
1700
+ return (_a = map[mode]) !== null && _a !== void 0 ? _a : 1;
1701
+ }
1702
+ function recoveryActionRequiredStateTransition(mode) {
1703
+ var map = {
1704
+ advance: 'current gate advances without repair after existing proof is accepted',
1705
+ collect_evidence: 'blockerFingerprint or evidenceHash changes with material proof, or run remains parked',
1706
+ read_only_diagnosis: 'diagnosis gate becomes valid or records a blocked-reproduction reason',
1707
+ repair_infra: 'infra preflight changes from failed/blocked to passed, or records a new infra blocker',
1708
+ repair_compile: 'compile/startup status changes from failed to passed, or records a new compile blocker',
1709
+ repair_journey_contract: 'journey contract validates with first/next/last workflow proof',
1710
+ repair_business_assertion: 'business assertion changes from missing/failed to passed with artifact proof',
1711
+ repair_release: 'hotfix/release gate changes from blocked to passed, rerun_release_gate, or parked manual',
1712
+ targeted_product_repair: 'owner-scoped diff is produced and deterministic proof advances to QA',
1713
+ manual_review: 'operator records one explicit decision',
1714
+ continue_gate: 'current gate records accepted proof and advances'
1715
+ };
1716
+ return map[mode] || 'runner records a validated state transition before continuing';
1717
+ }
1718
+ function recoveryActionProofRequiredBeforeContinuation(mode) {
1719
+ return mode !== 'advance' && mode !== 'continue_gate' && mode !== 'manual_review';
1720
+ }
1721
+ function recoveryActionExitCriteria(input) {
1722
+ return Array.from(new Set(__spreadArray(__spreadArray([
1723
+ "exact dispatch action ".concat(input.dispatchAction, " completed or was parked"),
1724
+ input.requiredStateTransition
1725
+ ], __read((recoveryActionProofRequiredBeforeContinuation(input.mode) ? ['do not continue runner until required proof artifact is attached'] : [])), false), __read(input.stopWhen), false).map(function (entry) { return cleanText(entry, 500); }).filter(Boolean))).slice(0, 30);
1726
+ }
1033
1727
  function buildResolveIOAIManagerRecoveryActionPacket(input) {
1034
1728
  var checkpoint = input.checkpoint;
1035
1729
  var probe = input.probe || buildResolveIOAIManagerRecoveryEvidenceProbe({
@@ -1061,6 +1755,15 @@ function buildResolveIOAIManagerRecoveryActionPacket(input) {
1061
1755
  publishStatus: checkpoint.lane
1062
1756
  })
1063
1757
  : undefined;
1758
+ var allowedDispatchAction = dispatchActionForMode(mode);
1759
+ var requiredStateTransition = recoveryActionRequiredStateTransition(mode);
1760
+ var proofRequiredBeforeContinuation = recoveryActionProofRequiredBeforeContinuation(mode);
1761
+ var exitCriteria = recoveryActionExitCriteria({
1762
+ mode: mode,
1763
+ dispatchAction: allowedDispatchAction,
1764
+ requiredStateTransition: requiredStateTransition,
1765
+ stopWhen: stopWhen
1766
+ });
1064
1767
  var now = isoNow(input.now);
1065
1768
  return __assign(__assign(__assign({ actionId: stableHash('mgr-action', {
1066
1769
  checkpointId: checkpoint.checkpointId,
@@ -1068,13 +1771,13 @@ function buildResolveIOAIManagerRecoveryActionPacket(input) {
1068
1771
  mode: mode,
1069
1772
  evidenceHash: checkpoint.evidenceHash,
1070
1773
  blockerFingerprint: checkpoint.blockerFingerprint
1071
- }), 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'
1774
+ }), checkpointId: checkpoint.checkpointId, probeId: probe.probeId, recoveryClass: checkpoint.recoveryClass, mode: mode, singleActionOnly: true, allowedDispatchAction: allowedDispatchAction, 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'
1072
1775
  ? probe.objective
1073
- : 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
1776
+ : 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', costCeilingUsd: recoveryActionCostCeilingUsd(mode), requiredStateTransition: requiredStateTransition, proofRequiredBeforeContinuation: proofRequiredBeforeContinuation, canResetLoopAfterEvidence: resetLoopWhen.length > 0, maxAttemptsBeforePark: checkpoint.maxAttemptsBeforePark, requiredArtifacts: probe.requiredArtifacts.slice(0, 20), nextCommands: releasePolicy
1074
1777
  ? Array.from(new Set(__spreadArray(__spreadArray([], __read(nextCommands), false), __read(releasePolicy.allowedActions), false))).slice(0, 12)
1075
1778
  : nextCommands, successCriteria: releasePolicy
1076
1779
  ? Array.from(new Set(__spreadArray(__spreadArray([], __read(probe.acceptanceEvidence), false), __read(releasePolicy.requiredEvidence), false))).slice(0, 20)
1077
- : probe.acceptanceEvidence.slice(0, 20), retryPolicy: {
1780
+ : probe.acceptanceEvidence.slice(0, 20), exitCriteria: exitCriteria, retryPolicy: {
1078
1781
  allowImmediateRetry: checkpoint.status !== 'parked' && mode !== 'manual_review',
1079
1782
  requireNewEvidence: requireNewEvidence,
1080
1783
  resetLoopWhen: resetLoopWhen,
@@ -1111,6 +1814,7 @@ function buildRecoveryDispatchRecord(action, dispatchAction, status, reason, cur
1111
1814
  }), actionId: action.actionId, checkpointId: action.checkpointId, probeId: action.probeId, mode: action.mode, dispatchAction: dispatchAction, status: status, evidenceHash: evidenceHash, blockerFingerprint: blockerFingerprint, productRepairAllowed: action.productRepairAllowed && dispatchAction === 'run_targeted_product_repair', expensiveModelAllowed: action.expensiveModelAllowed && dispatchAction !== 'run_evidence_probe', reason: reason, artifactPaths: artifactPaths }, (status === 'started' ? { startedAt: createdAt } : {})), (status === 'completed' ? { completedAt: createdAt } : {})), { createdAt: createdAt });
1112
1815
  }
1113
1816
  function decideResolveIOAIManagerRecoveryActionDispatch(input) {
1817
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
1114
1818
  var action = input.action;
1115
1819
  var history = Array.isArray(input.history) ? input.history.filter(Boolean).slice(-50) : [];
1116
1820
  var current = input.current || {};
@@ -1128,6 +1832,7 @@ function decideResolveIOAIManagerRecoveryActionDispatch(input) {
1128
1832
  };
1129
1833
  }
1130
1834
  var dispatchAction = dispatchActionForMode(action.mode);
1835
+ var allowedDispatchAction = action.allowedDispatchAction || dispatchAction;
1131
1836
  var evidenceHash = current.evidenceHash || action.checkpointId || action.actionId;
1132
1837
  var blockerFingerprint = resolveResolveIOAIManagerBlockerFingerprint(current, action.objective);
1133
1838
  var sameActionHistory = history.filter(function (entry) { return entry.actionId === action.actionId; });
@@ -1137,11 +1842,20 @@ function decideResolveIOAIManagerRecoveryActionDispatch(input) {
1137
1842
  var completedDispatch = sameEvidenceHistory.find(function (entry) { return entry.status === 'completed' || entry.status === 'failed'; });
1138
1843
  var newEvidence = sameActionHistory.length > 0 && sameEvidenceHistory.length === 0;
1139
1844
  var requiresNewEvidence = action.retryPolicy.requireNewEvidence === true;
1845
+ var sameEvidenceAlreadyAttempted = !!completedDispatch && requiresNewEvidence && !newEvidence;
1140
1846
  var manualOnly = action.mode === 'manual_review' || !action.autoRunnable;
1141
1847
  var productDispatch = dispatchAction === 'run_targeted_product_repair';
1142
1848
  var expensiveDispatch = !['run_evidence_probe', 'advance', 'continue_gate', 'park_manual'].includes(dispatchAction);
1143
- if (manualOnly && input.operatorApproved !== true) {
1144
- var record_1 = buildRecoveryDispatchRecord(action, 'park_manual', 'parked', 'recovery_dispatch_requires_manual_review', current, input.now);
1849
+ var evidenceAssessment = assessResolveIOAIManagerEvidenceChange(undefined, current, action.objective);
1850
+ var autonomyPolicy = input.autonomyPolicy
1851
+ ? decideResolveIOAIManagerAutonomyPolicy(__assign(__assign({}, (input.autonomyPolicy || {})), { dispatchAction: dispatchAction, projectedActionCostUsd: (_b = (_a = input.autonomyPolicy) === null || _a === void 0 ? void 0 : _a.projectedActionCostUsd) !== null && _b !== void 0 ? _b : action.costCeilingUsd, newEvidence: (_d = (_c = input.autonomyPolicy) === null || _c === void 0 ? void 0 : _c.newEvidence) !== null && _d !== void 0 ? _d : newEvidence, materialEvidence: (_f = (_e = input.autonomyPolicy) === null || _e === void 0 ? void 0 : _e.materialEvidence) !== null && _f !== void 0 ? _f : evidenceAssessment.material, evidenceStrength: (_h = (_g = input.autonomyPolicy) === null || _g === void 0 ? void 0 : _g.evidenceStrength) !== null && _h !== void 0 ? _h : evidenceAssessment.strength, evidenceSignals: (_k = (_j = input.autonomyPolicy) === null || _j === void 0 ? void 0 : _j.evidenceSignals) !== null && _k !== void 0 ? _k : evidenceAssessment.signals, sameEvidenceAlreadyAttempted: (_m = (_l = input.autonomyPolicy) === null || _l === void 0 ? void 0 : _l.sameEvidenceAlreadyAttempted) !== null && _m !== void 0 ? _m : sameEvidenceAlreadyAttempted, operatorApproved: input.operatorApproved }))
1852
+ : undefined;
1853
+ var autonomyBlocksDispatch = !!autonomyPolicy && (autonomyPolicy.mode === 'monitor_only'
1854
+ || (autonomyPolicy.requiresHumanApproval === true && input.operatorApproved !== true)
1855
+ || (autonomyPolicy.canAutoDispatch !== true && input.operatorApproved !== true)
1856
+ || (autonomyPolicy.blocked === true && autonomyPolicy.canManualDispatch !== true));
1857
+ if (autonomyBlocksDispatch) {
1858
+ var record_1 = buildRecoveryDispatchRecord(action, 'park_manual', 'parked', "recovery_dispatch_blocked_by_autonomy_policy:".concat((autonomyPolicy === null || autonomyPolicy === void 0 ? void 0 : autonomyPolicy.reason) || 'unknown'), current, input.now);
1145
1859
  return {
1146
1860
  dispatchAction: 'park_manual',
1147
1861
  allowed: false,
@@ -1152,11 +1866,12 @@ function decideResolveIOAIManagerRecoveryActionDispatch(input) {
1152
1866
  shouldRecordDispatch: true,
1153
1867
  requiresNewEvidence: requiresNewEvidence,
1154
1868
  newEvidence: newEvidence,
1869
+ autonomyPolicy: autonomyPolicy,
1155
1870
  dispatchRecord: record_1
1156
1871
  };
1157
1872
  }
1158
- if (productDispatch && action.productRepairAllowed !== true) {
1159
- var record_2 = buildRecoveryDispatchRecord(action, 'park_manual', 'parked', 'recovery_dispatch_product_repair_not_allowed', current, input.now);
1873
+ if (action.singleActionOnly === true && allowedDispatchAction !== dispatchAction) {
1874
+ var record_2 = buildRecoveryDispatchRecord(action, 'park_manual', 'parked', 'recovery_dispatch_action_not_in_packet_contract', current, input.now);
1160
1875
  return {
1161
1876
  dispatchAction: 'park_manual',
1162
1877
  allowed: false,
@@ -1167,9 +1882,42 @@ function decideResolveIOAIManagerRecoveryActionDispatch(input) {
1167
1882
  shouldRecordDispatch: true,
1168
1883
  requiresNewEvidence: true,
1169
1884
  newEvidence: newEvidence,
1885
+ autonomyPolicy: autonomyPolicy,
1170
1886
  dispatchRecord: record_2
1171
1887
  };
1172
1888
  }
1889
+ if (manualOnly && input.operatorApproved !== true) {
1890
+ var record_3 = buildRecoveryDispatchRecord(action, 'park_manual', 'parked', 'recovery_dispatch_requires_manual_review', current, input.now);
1891
+ return {
1892
+ dispatchAction: 'park_manual',
1893
+ allowed: false,
1894
+ reason: record_3.reason,
1895
+ status: 'parked',
1896
+ canRunProductRepair: false,
1897
+ canRunExpensiveModel: false,
1898
+ shouldRecordDispatch: true,
1899
+ requiresNewEvidence: requiresNewEvidence,
1900
+ newEvidence: newEvidence,
1901
+ autonomyPolicy: autonomyPolicy,
1902
+ dispatchRecord: record_3
1903
+ };
1904
+ }
1905
+ if (productDispatch && action.productRepairAllowed !== true) {
1906
+ var record_4 = buildRecoveryDispatchRecord(action, 'park_manual', 'parked', 'recovery_dispatch_product_repair_not_allowed', current, input.now);
1907
+ return {
1908
+ dispatchAction: 'park_manual',
1909
+ allowed: false,
1910
+ reason: record_4.reason,
1911
+ status: 'parked',
1912
+ canRunProductRepair: false,
1913
+ canRunExpensiveModel: false,
1914
+ shouldRecordDispatch: true,
1915
+ requiresNewEvidence: true,
1916
+ newEvidence: newEvidence,
1917
+ autonomyPolicy: autonomyPolicy,
1918
+ dispatchRecord: record_4
1919
+ };
1920
+ }
1173
1921
  if (activeDispatch) {
1174
1922
  return {
1175
1923
  dispatchAction: 'park_manual',
@@ -1180,22 +1928,24 @@ function decideResolveIOAIManagerRecoveryActionDispatch(input) {
1180
1928
  canRunExpensiveModel: false,
1181
1929
  shouldRecordDispatch: false,
1182
1930
  requiresNewEvidence: true,
1183
- newEvidence: false
1931
+ newEvidence: false,
1932
+ autonomyPolicy: autonomyPolicy
1184
1933
  };
1185
1934
  }
1186
- if (completedDispatch && requiresNewEvidence && !newEvidence) {
1187
- var record_3 = buildRecoveryDispatchRecord(action, 'park_manual', 'parked', 'recovery_dispatch_same_evidence_already_attempted', current, input.now);
1935
+ if (sameEvidenceAlreadyAttempted) {
1936
+ var record_5 = buildRecoveryDispatchRecord(action, 'park_manual', 'parked', 'recovery_dispatch_same_evidence_already_attempted', current, input.now);
1188
1937
  return {
1189
1938
  dispatchAction: 'park_manual',
1190
1939
  allowed: false,
1191
- reason: record_3.reason,
1940
+ reason: record_5.reason,
1192
1941
  status: 'parked',
1193
1942
  canRunProductRepair: false,
1194
1943
  canRunExpensiveModel: false,
1195
1944
  shouldRecordDispatch: true,
1196
1945
  requiresNewEvidence: true,
1197
1946
  newEvidence: false,
1198
- dispatchRecord: record_3
1947
+ autonomyPolicy: autonomyPolicy,
1948
+ dispatchRecord: record_5
1199
1949
  };
1200
1950
  }
1201
1951
  var status = dispatchAction === 'advance' || dispatchAction === 'continue_gate'
@@ -1212,6 +1962,7 @@ function decideResolveIOAIManagerRecoveryActionDispatch(input) {
1212
1962
  shouldRecordDispatch: true,
1213
1963
  requiresNewEvidence: requiresNewEvidence,
1214
1964
  newEvidence: newEvidence,
1965
+ autonomyPolicy: autonomyPolicy,
1215
1966
  dispatchRecord: record
1216
1967
  };
1217
1968
  }
@@ -1258,6 +2009,7 @@ function buildResolveIOAIManagerRecoveryExecutionDirective(input) {
1258
2009
  var dispatchDecision = input.dispatchDecision || decideResolveIOAIManagerRecoveryActionDispatch({
1259
2010
  action: action,
1260
2011
  current: input.current,
2012
+ autonomyPolicy: input.autonomyPolicy,
1261
2013
  now: input.now
1262
2014
  });
1263
2015
  var dispatchAction = dispatchDecision.dispatchAction;
@@ -1267,17 +2019,17 @@ function buildResolveIOAIManagerRecoveryExecutionDirective(input) {
1267
2019
  var stepType = cleanText((action === null || action === void 0 ? void 0 : action.stepType) || ((_b = input.current) === null || _b === void 0 ? void 0 : _b.stepType) || '', 120);
1268
2020
  var rerunReason = recoveryDirectiveReason(action, dispatchDecision, input.current);
1269
2021
  var surface = cleanText(input.surface || 'runner', 120);
1270
- return __assign(__assign(__assign({ directiveId: stableHash('mgr-directive', {
2022
+ return __assign(__assign(__assign(__assign(__assign({ directiveId: stableHash('mgr-directive', {
1271
2023
  surface: surface,
1272
2024
  actionId: (action === null || action === void 0 ? void 0 : action.actionId) || '',
1273
2025
  dispatchAction: dispatchAction,
1274
2026
  reason: dispatchDecision.reason,
1275
2027
  evidenceHash: ((_c = dispatchDecision.dispatchRecord) === null || _c === void 0 ? void 0 : _c.evidenceHash) || ((_d = input.current) === null || _d === void 0 ? void 0 : _d.evidenceHash) || ''
1276
- }), 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
2028
+ }), surface: surface, dispatchAction: dispatchAction, phase: phase, allowed: dispatchDecision.allowed, status: dispatchDecision.status, reason: dispatchDecision.reason, singleActionOnly: (action === null || action === void 0 ? void 0 : action.singleActionOnly) !== false, allowedDispatchAction: (action === null || action === void 0 ? void 0 : action.allowedDispatchAction) || dispatchAction, 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, costCeilingUsd: Math.max(0, Number((action === null || action === void 0 ? void 0 : action.costCeilingUsd) || 0) || 0), requiredStateTransition: cleanText(action === null || action === void 0 ? void 0 : action.requiredStateTransition, 500), proofRequiredBeforeContinuation: (action === null || action === void 0 ? void 0 : action.proofRequiredBeforeContinuation) === true, canRunProductRepair: dispatchDecision.canRunProductRepair, canRunExpensiveModel: dispatchDecision.canRunExpensiveModel, canResetLoopAfterEvidence: (action === null || action === void 0 ? void 0 : action.canResetLoopAfterEvidence) === true, requiresNewEvidence: dispatchDecision.requiresNewEvidence, newEvidence: dispatchDecision.newEvidence }, (dispatchDecision.autonomyPolicy ? { autonomyPolicy: dispatchDecision.autonomyPolicy } : {})), { 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), exitCriteria: cleanList(action === null || action === void 0 ? void 0 : action.exitCriteria, 30, 500), forbiddenActions: (action === null || action === void 0 ? void 0 : action.productRepairAllowed) === true
1277
2029
  ? []
1278
2030
  : Array.from(new Set(__spreadArray([
1279
2031
  'Do not run product-code repair from this directive unless canRunProductRepair is true.'
1280
- ], __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 });
2032
+ ], __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 });
1281
2033
  }
1282
2034
  function newListEntries(current, previous) {
1283
2035
  var existing = new Set(previous.map(function (entry) { return cleanText(entry, 500); }).filter(Boolean));