@resolveio/server-lib 22.3.157 → 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,14 +47,17 @@ 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.selectResolveIOSupportSimilarCaseHints = selectResolveIOSupportSimilarCaseHints;
50
51
  exports.evaluateResolveIOSupportDiagnosisEvidenceQuality = evaluateResolveIOSupportDiagnosisEvidenceQuality;
51
52
  exports.normalizeResolveIOSupportDiagnosisGate = normalizeResolveIOSupportDiagnosisGate;
52
53
  exports.extractResolveIOSupportDiagnosisGateFromText = extractResolveIOSupportDiagnosisGateFromText;
53
54
  exports.validateResolveIOSupportDiagnosisGate = validateResolveIOSupportDiagnosisGate;
55
+ exports.evaluateResolveIOSupportBusinessProofReadiness = evaluateResolveIOSupportBusinessProofReadiness;
54
56
  exports.decideResolveIOSupportCustomerReplyPolicy = decideResolveIOSupportCustomerReplyPolicy;
55
57
  exports.buildResolveIOSupportIssueClassProbes = buildResolveIOSupportIssueClassProbes;
56
58
  exports.hashResolveIOSupportV5Evidence = hashResolveIOSupportV5Evidence;
57
59
  exports.decideResolveIOSupportV5RepeatedFailureStop = decideResolveIOSupportV5RepeatedFailureStop;
60
+ exports.evaluateResolveIOSupportEvidenceFreshness = evaluateResolveIOSupportEvidenceFreshness;
58
61
  exports.changedFilesOutsideResolveIOSupportDiagnosisOwnerFiles = changedFilesOutsideResolveIOSupportDiagnosisOwnerFiles;
59
62
  exports.decideResolveIOSupportV5RepairGate = decideResolveIOSupportV5RepairGate;
60
63
  exports.applyResolveIOSupportDiagnosisGateToMicrotasks = applyResolveIOSupportDiagnosisGateToMicrotasks;
@@ -68,6 +71,7 @@ exports.initializeResolveIOSupportV5State = initializeResolveIOSupportV5State;
68
71
  exports.recordResolveIOSupportV5Step = recordResolveIOSupportV5Step;
69
72
  exports.recordResolveIOSupportV5MicrotaskUsage = recordResolveIOSupportV5MicrotaskUsage;
70
73
  exports.decideResolveIOSupportV5Continuation = decideResolveIOSupportV5Continuation;
74
+ exports.decideResolveIOSupportV5AutonomousNextAction = decideResolveIOSupportV5AutonomousNextAction;
71
75
  exports.buildResolveIOSupportV5DiagnoseFirstPrompt = buildResolveIOSupportV5DiagnoseFirstPrompt;
72
76
  exports.buildResolveIOSupportV5MicrotaskPrompt = buildResolveIOSupportV5MicrotaskPrompt;
73
77
  exports.summarizeResolveIOSupportV5MicrotaskUsage = summarizeResolveIOSupportV5MicrotaskUsage;
@@ -227,6 +231,199 @@ function normalizeSupportDiagnosisHints(values) {
227
231
  .filter(function (entry) { return entry.id || entry.ticketNumber || entry.title || entry.reason || entry.commitSha; })
228
232
  .slice(0, 8);
229
233
  }
234
+ function normalizeSupportSimilarCaseSource(value) {
235
+ var normalized = cleanText(value, 80).toLowerCase();
236
+ if (/commit|git/.test(normalized)) {
237
+ return 'git_commit';
238
+ }
239
+ if (/ticket/.test(normalized)) {
240
+ return 'support_ticket';
241
+ }
242
+ if (/airun|ai_run|run/.test(normalized)) {
243
+ return 'airun';
244
+ }
245
+ return 'manual';
246
+ }
247
+ function supportOutcomeLooksAccepted(value) {
248
+ return /^(accepted|pass|passed|complete|completed|merged|released)$/i.test(cleanText(value, 80));
249
+ }
250
+ function supportOutcomeLooksRejected(value) {
251
+ return /\b(reject|rejected|false_pass|failed|failure|blocked|unknown|stopped|manual_handoff)\b/i.test(cleanText(value, 120));
252
+ }
253
+ function supportOwnerFileDirectory(value) {
254
+ var normalized = normalizeOwnerFilePath(value);
255
+ var parts = normalized.split('/').filter(Boolean);
256
+ return parts.length > 1 ? parts.slice(0, -1).join('/') : normalized;
257
+ }
258
+ function supportTextTokens(value) {
259
+ var stop = new Set(['the', 'and', 'for', 'with', 'that', 'this', 'from', 'into', 'when', 'where', 'what', 'have', 'has', 'had', 'not', 'but', 'are', 'was', 'were', 'issue', 'ticket', 'support']);
260
+ return Array.from(new Set(cleanText(value, 3000).toLowerCase()
261
+ .split(/[^a-z0-9_/-]+/g)
262
+ .map(function (token) { return token.trim(); })
263
+ .filter(function (token) { return token.length >= 3 && !stop.has(token); })))
264
+ .slice(0, 80);
265
+ }
266
+ function normalizeResolveIOSupportSimilarCaseCandidate(value) {
267
+ var _a, _b;
268
+ var source = cleanObject(value);
269
+ if (!Object.keys(source).length && typeof value !== 'string') {
270
+ return undefined;
271
+ }
272
+ if (typeof value === 'string') {
273
+ var summary = cleanText(value, 500);
274
+ return summary ? {
275
+ source: 'manual',
276
+ title: summary,
277
+ summary: summary,
278
+ keywords: supportTextTokens(summary)
279
+ } : undefined;
280
+ }
281
+ var metadata = cleanObject(source.metadata);
282
+ var runSourceIds = cleanObject(source.sourceIds || source.source_ids || metadata.sourceIds || metadata.source_ids);
283
+ var diagnosis = cleanObject(source.diagnosisGate || source.diagnosis_gate || source.supportV5DiagnosisGate || source.support_v5_diagnosis_gate || metadata.diagnosisGate || metadata.diagnosis_gate);
284
+ var sourceIds = cleanObject(source.sourceIds || source.source_ids || metadata.sourceIds || metadata.source_ids);
285
+ var sourceText = [
286
+ source.title,
287
+ source.summary,
288
+ source.message,
289
+ source.description,
290
+ source.reason,
291
+ source.commitMessage,
292
+ source.commit_message,
293
+ (_a = diagnosis.issue_case) === null || _a === void 0 ? void 0 : _a.customer_complaint,
294
+ (_b = diagnosis.accepted_hypothesis) === null || _b === void 0 ? void 0 : _b.statement
295
+ ].filter(Boolean).join(' ');
296
+ var ownerFiles = cleanList(source.ownerFiles
297
+ || source.owner_files
298
+ || source.files
299
+ || diagnosis.owner_files
300
+ || diagnosis.ownerFiles
301
+ || metadata.ownerFiles
302
+ || metadata.owner_files, 12, 300).map(normalizeOwnerFilePath).filter(Boolean);
303
+ var issueClass = cleanText(source.issueClass
304
+ || source.issue_class
305
+ || diagnosis.issue_class
306
+ || diagnosis.issueClass
307
+ || metadata.issueClass
308
+ || metadata.issue_class, 80);
309
+ var candidate = {
310
+ source: normalizeSupportSimilarCaseSource(source.source || source.type || source.runSource),
311
+ id: cleanText(source.id || source._id || source.runId || source.run_id, 160),
312
+ ticketNumber: cleanText(source.ticketNumber || source.ticket_number || source.sourceTicketNumber || sourceIds.ticketNumber || runSourceIds.ticketNumber, 80),
313
+ title: cleanText(source.title || source.name || source.summary, 300),
314
+ outcome: cleanText(source.outcome || source.status || source.outcomeLabel || source.outcome_label, 80),
315
+ issueClass: normalizeIssueClass(issueClass) || cleanText(issueClass, 80),
316
+ ownerFiles: ownerFiles,
317
+ commitSha: cleanText(source.commitSha || source.commit_sha || source.sha || source.sourceCommitSha || source.source_commit_sha, 80),
318
+ commitMessage: cleanText(source.commitMessage || source.commit_message || source.message, 300),
319
+ reason: cleanText(source.reason || source.matchReason || source.match_reason, 500),
320
+ summary: cleanText(source.summary || source.description || source.message || sourceText, 800),
321
+ keywords: cleanList(source.keywords || source.tags, 20, 80).concat(supportTextTokens(sourceText)).slice(0, 40),
322
+ updatedAt: isoNow(source.updatedAt || source.updated_at || source.recordedAt || source.recorded_at || source.createdAt || source.created_at),
323
+ metadata: metadata
324
+ };
325
+ if (!candidate.id && !candidate.ticketNumber && !candidate.title && !candidate.commitSha && !candidate.summary) {
326
+ return undefined;
327
+ }
328
+ if (candidate.commitSha && candidate.source === 'manual') {
329
+ candidate.source = 'git_commit';
330
+ }
331
+ if (candidate.ticketNumber && candidate.source === 'manual') {
332
+ candidate.source = 'support_ticket';
333
+ }
334
+ return candidate;
335
+ }
336
+ function selectResolveIOSupportSimilarCaseHints(input) {
337
+ var e_3, _a;
338
+ if (input === void 0) { input = {}; }
339
+ var issueClass = normalizeIssueClass(input.issueClass);
340
+ var ownerFiles = cleanList(input.ownerFiles, 12, 300).map(normalizeOwnerFilePath).filter(Boolean);
341
+ var ownerFileSet = new Set(ownerFiles);
342
+ var ownerDirs = new Set(ownerFiles.map(supportOwnerFileDirectory).filter(Boolean));
343
+ var textTokens = new Set(supportTextTokens(input.text));
344
+ var limit = Math.max(1, Math.min(12, Number(input.limit || 6)));
345
+ var normalized = (Array.isArray(input.candidates) ? input.candidates : [])
346
+ .map(normalizeResolveIOSupportSimilarCaseCandidate)
347
+ .filter(function (candidate) { return !!candidate; });
348
+ var ranked = [];
349
+ var ignoredCount = 0;
350
+ try {
351
+ for (var normalized_1 = __values(normalized), normalized_1_1 = normalized_1.next(); !normalized_1_1.done; normalized_1_1 = normalized_1.next()) {
352
+ var candidate = normalized_1_1.value;
353
+ var outcomeKnown = !!candidate.outcome;
354
+ var accepted = supportOutcomeLooksAccepted(candidate.outcome) || (!!candidate.commitSha && !supportOutcomeLooksRejected(candidate.outcome));
355
+ if (outcomeKnown && !accepted) {
356
+ ignoredCount += 1;
357
+ continue;
358
+ }
359
+ var signals = [];
360
+ var score = accepted ? 100 : 40;
361
+ var candidateIssueClass = normalizeIssueClass(candidate.issueClass);
362
+ if (issueClass && candidateIssueClass && issueClass === candidateIssueClass) {
363
+ score += 45;
364
+ signals.push("issue_class:".concat(issueClass));
365
+ }
366
+ var exactOwnerOverlap = candidate.ownerFiles.filter(function (file) { return ownerFileSet.has(normalizeOwnerFilePath(file)); });
367
+ if (exactOwnerOverlap.length) {
368
+ score += 35 + Math.min(20, exactOwnerOverlap.length * 5);
369
+ signals.push("owner_file_overlap:".concat(exactOwnerOverlap.slice(0, 3).join(',')));
370
+ }
371
+ var directoryOverlap = candidate.ownerFiles
372
+ .map(supportOwnerFileDirectory)
373
+ .filter(function (dir) { return dir && ownerDirs.has(dir); });
374
+ if (directoryOverlap.length && !exactOwnerOverlap.length) {
375
+ score += 18;
376
+ signals.push("owner_dir_overlap:".concat(Array.from(new Set(directoryOverlap)).slice(0, 2).join(',')));
377
+ }
378
+ var candidateTokens = new Set(__spreadArray(__spreadArray([], __read((candidate.keywords || [])), false), __read(supportTextTokens([candidate.title, candidate.summary, candidate.commitMessage].join(' '))), false));
379
+ var tokenOverlap = Array.from(candidateTokens).filter(function (token) { return textTokens.has(token); }).slice(0, 6);
380
+ if (tokenOverlap.length) {
381
+ score += Math.min(18, tokenOverlap.length * 3);
382
+ signals.push("weak_text_overlap:".concat(tokenOverlap.join(',')));
383
+ }
384
+ if (candidate.commitSha) {
385
+ score += 8;
386
+ signals.push('commit_linked');
387
+ }
388
+ if (!signals.length && score < 100) {
389
+ ignoredCount += 1;
390
+ continue;
391
+ }
392
+ ranked.push({
393
+ id: candidate.id,
394
+ ticketNumber: candidate.ticketNumber,
395
+ title: candidate.title,
396
+ outcome: candidate.outcome || (candidate.commitSha ? 'commit_hint' : ''),
397
+ issueClass: candidateIssueClass || candidate.issueClass,
398
+ ownerFiles: candidate.ownerFiles.slice(0, 8),
399
+ commitSha: candidate.commitSha,
400
+ commitMessage: candidate.commitMessage,
401
+ reason: signals.join('; '),
402
+ source: candidate.source,
403
+ score: score,
404
+ structuredSignals: signals,
405
+ advisoryOnly: true
406
+ });
407
+ }
408
+ }
409
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
410
+ finally {
411
+ try {
412
+ if (normalized_1_1 && !normalized_1_1.done && (_a = normalized_1.return)) _a.call(normalized_1);
413
+ }
414
+ finally { if (e_3) throw e_3.error; }
415
+ }
416
+ var sorted = ranked
417
+ .sort(function (a, b) { return b.score - a.score || String(b.ticketNumber || b.commitSha || '').localeCompare(String(a.ticketNumber || a.commitSha || '')); })
418
+ .slice(0, limit);
419
+ return {
420
+ ranked: sorted,
421
+ similarTickets: sorted.filter(function (hint) { return hint.source !== 'git_commit'; }).slice(0, limit),
422
+ similarCommits: sorted.filter(function (hint) { return hint.source === 'git_commit' || !!hint.commitSha; }).slice(0, limit),
423
+ ignoredCount: ignoredCount,
424
+ generatedAt: isoNow(input.now)
425
+ };
426
+ }
230
427
  function normalizeSupportDiagnosisBusinessProofContract(value, issueClassHint) {
231
428
  var source = cleanObject(value);
232
429
  if (!Object.keys(source).length) {
@@ -407,7 +604,7 @@ function normalizeResolveIOSupportDiagnosisGate(value, now) {
407
604
  return gate;
408
605
  }
409
606
  function extractResolveIOSupportDiagnosisGateFromText(value, now) {
410
- var e_3, _a;
607
+ var e_4, _a;
411
608
  var text = String(value || '').trim();
412
609
  if (!text) {
413
610
  return undefined;
@@ -435,12 +632,12 @@ function extractResolveIOSupportDiagnosisGateFromText(value, now) {
435
632
  }
436
633
  }
437
634
  }
438
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
635
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
439
636
  finally {
440
637
  try {
441
638
  if (candidates_1_1 && !candidates_1_1.done && (_a = candidates_1.return)) _a.call(candidates_1);
442
639
  }
443
- finally { if (e_3) throw e_3.error; }
640
+ finally { if (e_4) throw e_4.error; }
444
641
  }
445
642
  return undefined;
446
643
  }
@@ -583,11 +780,289 @@ function normalizeSupportConfidenceLevel(value) {
583
780
  return normalized ? 'unknown' : 'unknown';
584
781
  }
585
782
  function supportReleaseLooksBlocked(value) {
586
- return /\b(fail|failed|error|blocked|missing|empty|stale|denied|timeout|pending_manual|requested|in_progress|queued)\b/i.test(cleanText(value, 200));
783
+ return /\b(fail|failed|error|blocked|missing|empty|stale|denied|timeout)\b/i.test(cleanText(value, 200));
587
784
  }
588
785
  function supportBusinessAssertionPassed(value) {
589
786
  return /^(pass|passed|accepted|business_assertion_passed)$/i.test(cleanText(value, 80));
590
787
  }
788
+ function supportBusinessAssertionFailed(value) {
789
+ return /^(fail|failed|blocked|needs_repair|business_assertion_failed)$/i.test(cleanText(value, 80));
790
+ }
791
+ function supportBusinessAssertionRouteOnly(value) {
792
+ return /^(route_probe_pass|route_only_pass|route_pass|route_probe|route_loaded)$/i.test(cleanText(value, 80));
793
+ }
794
+ function normalizeSupportBusinessProofAssertions(input) {
795
+ var e_5, _a;
796
+ var gate = normalizeResolveIOSupportDiagnosisGate(input.diagnosisGate);
797
+ var proofPlan = gate === null || gate === void 0 ? void 0 : gate.proof_plan;
798
+ var proofContract = proofPlan === null || proofPlan === void 0 ? void 0 : proofPlan.business_proof_contract;
799
+ var artifactPaths = cleanList(input.businessProofArtifacts, 30, 500);
800
+ var assertions = [];
801
+ try {
802
+ for (var _b = __values(Array.isArray(input.businessAssertions) ? input.businessAssertions : []), _c = _b.next(); !_c.done; _c = _b.next()) {
803
+ var entry = _c.value;
804
+ var source = cleanObject(entry);
805
+ if (!Object.keys(source).length) {
806
+ continue;
807
+ }
808
+ var metadata = cleanObject(source.metadata);
809
+ assertions.push({
810
+ assertion: pickText(source, ['assertion', 'name', 'workflow', 'expected'], 1000) || (proofPlan === null || proofPlan === void 0 ? void 0 : proofPlan.business_assertion) || 'business assertion',
811
+ status: cleanText(source.status || source.outcome || source.result, 80),
812
+ workflow: pickText(source, ['workflow', 'workflowName'], 400),
813
+ route: pickText(source, ['route', 'url'], 500),
814
+ before: pickText(source, ['before', 'before_state', 'beforeState'], 1000),
815
+ action: pickText(source, ['action', 'action_under_test', 'actionUnderTest'], 1000),
816
+ expected: pickText(source, ['expected', 'expected_business_state_change', 'expectedBusinessStateChange'], 1000),
817
+ after: pickText(source, ['after', 'after_state', 'afterState'], 1000),
818
+ observed: pickText(source, ['observed', 'actual'], 1000),
819
+ dataProof: pickText(source, ['dataProof', 'data_proof', 'proof', 'domProof', 'dom_proof'], 1400),
820
+ mongoDelta: cleanObject(source.mongoDelta || source.mongo_delta),
821
+ artifactPaths: cleanList(source.artifactPaths || source.artifact_paths || source.artifacts, 30, 500),
822
+ message: pickText(source, ['message', 'reason', 'summary'], 1000),
823
+ acceptanceBlocked: source.acceptanceBlocked === true || source.acceptance_blocked === true || metadata.acceptanceBlocked === true || metadata.acceptance_blocked === true,
824
+ routeOnly: source.routeOnly === true || source.route_only === true || source.outcome === 'route_only_pass' || source.status === 'route_probe_pass' || metadata.routeOnly === true || metadata.route_only === true,
825
+ metadata: metadata
826
+ });
827
+ }
828
+ }
829
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
830
+ finally {
831
+ try {
832
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
833
+ }
834
+ finally { if (e_5) throw e_5.error; }
835
+ }
836
+ var status = cleanText(input.businessAssertionStatus || input.outcomeLabel, 80);
837
+ if (!assertions.length && (supportBusinessAssertionPassed(status) || supportBusinessAssertionRouteOnly(status) || supportBusinessAssertionFailed(status))) {
838
+ assertions.push({
839
+ assertion: (proofPlan === null || proofPlan === void 0 ? void 0 : proofPlan.business_assertion) || (proofContract === null || proofContract === void 0 ? void 0 : proofContract.data_or_dom_assertion) || 'business assertion',
840
+ status: status,
841
+ workflow: proofContract === null || proofContract === void 0 ? void 0 : proofContract.action_under_test,
842
+ route: (proofPlan === null || proofPlan === void 0 ? void 0 : proofPlan.route) || (gate === null || gate === void 0 ? void 0 : gate.issue_case.route_module),
843
+ before: proofPlan === null || proofPlan === void 0 ? void 0 : proofPlan.before,
844
+ action: (proofPlan === null || proofPlan === void 0 ? void 0 : proofPlan.action) || (proofContract === null || proofContract === void 0 ? void 0 : proofContract.action_under_test),
845
+ expected: (proofContract === null || proofContract === void 0 ? void 0 : proofContract.expected_business_state_change) || (proofPlan === null || proofPlan === void 0 ? void 0 : proofPlan.after),
846
+ after: proofPlan === null || proofPlan === void 0 ? void 0 : proofPlan.after,
847
+ observed: '',
848
+ dataProof: (proofContract === null || proofContract === void 0 ? void 0 : proofContract.data_or_dom_assertion) || (proofPlan === null || proofPlan === void 0 ? void 0 : proofPlan.data_assertion) || '',
849
+ mongoDelta: {},
850
+ artifactPaths: artifactPaths,
851
+ message: '',
852
+ acceptanceBlocked: supportBusinessAssertionRouteOnly(status),
853
+ routeOnly: supportBusinessAssertionRouteOnly(status),
854
+ metadata: {}
855
+ });
856
+ }
857
+ return assertions;
858
+ }
859
+ function supportBusinessProofAssertionText(assertion) {
860
+ return cleanText([
861
+ assertion.assertion,
862
+ assertion.workflow,
863
+ assertion.before,
864
+ assertion.action,
865
+ assertion.expected,
866
+ assertion.after,
867
+ assertion.observed,
868
+ assertion.dataProof,
869
+ assertion.message
870
+ ].filter(Boolean).join(' '), 4000);
871
+ }
872
+ function supportBusinessProofAssertionMatchesContract(assertion, gate) {
873
+ var e_6, _a;
874
+ if (!gate) {
875
+ return false;
876
+ }
877
+ var metadata = assertion.metadata || {};
878
+ if (metadata.supportDiagnosisProof === true
879
+ || metadata.support_diagnosis_proof === true
880
+ || metadata.diagnosisProofPlanMatched === true
881
+ || metadata.diagnosis_proof_plan_matched === true
882
+ || metadata.proofPlanMatched === true
883
+ || metadata.proof_plan_matched === true) {
884
+ return true;
885
+ }
886
+ var proofPlan = gate.proof_plan;
887
+ var proofContract = proofPlan.business_proof_contract;
888
+ var requiredParts = [
889
+ proofPlan.business_assertion,
890
+ proofPlan.after,
891
+ proofPlan.data_assertion,
892
+ proofContract === null || proofContract === void 0 ? void 0 : proofContract.expected_business_state_change,
893
+ proofContract === null || proofContract === void 0 ? void 0 : proofContract.data_or_dom_assertion
894
+ ].map(function (part) { return cleanText(part, 1000).toLowerCase(); }).filter(function (part) { return part.length >= 12; });
895
+ var assertionText = supportBusinessProofAssertionText(assertion).toLowerCase();
896
+ if (!requiredParts.length) {
897
+ return false;
898
+ }
899
+ if (requiredParts.some(function (part) { return assertionText.includes(part); })) {
900
+ return true;
901
+ }
902
+ var proofWords = new Set(requiredParts.join(' ').split(/[^a-z0-9]+/g).filter(function (word) { return word.length >= 5; }));
903
+ var assertionWords = new Set(assertionText.split(/[^a-z0-9]+/g).filter(function (word) { return word.length >= 5; }));
904
+ var overlap = 0;
905
+ try {
906
+ for (var proofWords_1 = __values(proofWords), proofWords_1_1 = proofWords_1.next(); !proofWords_1_1.done; proofWords_1_1 = proofWords_1.next()) {
907
+ var word = proofWords_1_1.value;
908
+ if (assertionWords.has(word)) {
909
+ overlap += 1;
910
+ }
911
+ }
912
+ }
913
+ catch (e_6_1) { e_6 = { error: e_6_1 }; }
914
+ finally {
915
+ try {
916
+ if (proofWords_1_1 && !proofWords_1_1.done && (_a = proofWords_1.return)) _a.call(proofWords_1);
917
+ }
918
+ finally { if (e_6) throw e_6.error; }
919
+ }
920
+ return overlap >= Math.min(5, Math.max(3, Math.ceil(proofWords.size * 0.45)));
921
+ }
922
+ function supportBusinessProofArtifactFingerprint(paths) {
923
+ var normalized = cleanList(paths, 80, 500).sort();
924
+ return normalized.length ? hashResolveIOSupportV5Evidence({ artifacts: normalized }) : '';
925
+ }
926
+ function supportBusinessProofFingerprint(gate, assertion, artifactPaths) {
927
+ var _a;
928
+ if (artifactPaths === void 0) { artifactPaths = []; }
929
+ if (!gate || !assertion) {
930
+ return '';
931
+ }
932
+ var proofPlan = gate.proof_plan;
933
+ var proofContract = proofPlan.business_proof_contract;
934
+ return hashResolveIOSupportV5Evidence({
935
+ issueClass: gate.issue_class,
936
+ proofPlan: {
937
+ before: proofPlan.before,
938
+ action: proofPlan.action,
939
+ after: proofPlan.after,
940
+ businessAssertion: proofPlan.business_assertion,
941
+ dataAssertion: proofPlan.data_assertion,
942
+ contractAction: proofContract === null || proofContract === void 0 ? void 0 : proofContract.action_under_test,
943
+ contractExpected: proofContract === null || proofContract === void 0 ? void 0 : proofContract.expected_business_state_change,
944
+ contractAssertion: proofContract === null || proofContract === void 0 ? void 0 : proofContract.data_or_dom_assertion
945
+ },
946
+ assertion: {
947
+ assertion: assertion.assertion,
948
+ status: assertion.status,
949
+ workflow: assertion.workflow,
950
+ route: assertion.route,
951
+ before: assertion.before,
952
+ action: assertion.action,
953
+ expected: assertion.expected,
954
+ after: assertion.after,
955
+ observed: assertion.observed,
956
+ dataProof: assertion.dataProof,
957
+ mongoDelta: assertion.mongoDelta
958
+ },
959
+ artifacts: cleanList(((_a = assertion.artifactPaths) === null || _a === void 0 ? void 0 : _a.length) ? assertion.artifactPaths : artifactPaths, 80, 500).sort()
960
+ });
961
+ }
962
+ function defaultSupportBusinessProofReadinessFields(values) {
963
+ if (values === void 0) { values = {}; }
964
+ var artifactPaths = cleanList(values.artifactPaths, 80, 500);
965
+ return {
966
+ artifactPaths: artifactPaths,
967
+ proofFingerprint: cleanText(values.proofFingerprint, 160),
968
+ artifactFingerprint: cleanText(values.artifactFingerprint, 160) || supportBusinessProofArtifactFingerprint(artifactPaths),
969
+ proofFreshness: values.proofFreshness || (artifactPaths.length ? 'unknown' : 'missing')
970
+ };
971
+ }
972
+ function evaluateResolveIOSupportBusinessProofReadiness(input) {
973
+ if (input === void 0) { input = {}; }
974
+ var diagnosisValidation = validateResolveIOSupportDiagnosisGate(input.diagnosisGate);
975
+ var gate = diagnosisValidation.normalized;
976
+ var requiredEvidence = [
977
+ 'valid SupportDiagnosisGate proof_plan',
978
+ 'AIQaBusinessAssertion status=pass',
979
+ 'business assertion maps to diagnosis proof_plan/business_proof_contract',
980
+ 'artifact path for browser/data proof',
981
+ 'DOM/data proof or Mongo delta for the expected business state change'
982
+ ];
983
+ if (!diagnosisValidation.valid || !gate) {
984
+ return __assign({ ready: false, status: 'blocked', reason: 'support_business_proof_waiting_on_valid_diagnosis', blockers: diagnosisValidation.blockers.length ? diagnosisValidation.blockers : ['Valid SupportDiagnosisGate is required before business proof can accept the ticket.'], requiredEvidence: requiredEvidence }, defaultSupportBusinessProofReadinessFields());
985
+ }
986
+ var assertions = normalizeSupportBusinessProofAssertions(input);
987
+ if (!assertions.length) {
988
+ return __assign({ ready: false, status: 'missing', reason: 'support_business_proof_missing_aiqa_business_assertion', blockers: ['No AIQaBusinessAssertion was recorded for the diagnosis proof_plan.'], requiredEvidence: requiredEvidence }, defaultSupportBusinessProofReadinessFields());
989
+ }
990
+ var artifactPaths = Array.from(new Set(assertions.flatMap(function (assertion) { return assertion.artifactPaths || []; })));
991
+ var artifactFingerprint = supportBusinessProofArtifactFingerprint(artifactPaths);
992
+ var failed = assertions.find(function (assertion) { return supportBusinessAssertionFailed(assertion.status); });
993
+ if (failed) {
994
+ var failedFingerprint = supportBusinessProofFingerprint(gate, failed, artifactPaths);
995
+ return __assign(__assign({ ready: false, status: 'failed', reason: 'support_business_proof_assertion_failed', blockers: [failed.message || failed.observed || failed.assertion || 'Business assertion failed.'], requiredEvidence: requiredEvidence }, defaultSupportBusinessProofReadinessFields({
996
+ artifactPaths: artifactPaths,
997
+ proofFingerprint: failedFingerprint,
998
+ artifactFingerprint: artifactFingerprint,
999
+ proofFreshness: 'fresh'
1000
+ })), { matchedAssertion: failed });
1001
+ }
1002
+ var routeOnly = assertions.find(function (assertion) { return assertion.routeOnly || assertion.acceptanceBlocked || supportBusinessAssertionRouteOnly(assertion.status) || proofPlanLooksRouteOnly({
1003
+ before: assertion.before || '',
1004
+ action: assertion.action || '',
1005
+ after: assertion.after || assertion.expected || '',
1006
+ business_assertion: assertion.assertion || assertion.message || '',
1007
+ data_assertion: assertion.dataProof || '',
1008
+ artifact_expectation: assertion.artifactPaths.join(', ')
1009
+ }); });
1010
+ if (routeOnly) {
1011
+ var routeOnlyFingerprint = supportBusinessProofFingerprint(gate, routeOnly, artifactPaths);
1012
+ return __assign(__assign({ ready: false, status: 'route_only', reason: 'support_business_proof_route_only_or_acceptance_blocked', blockers: ['Route probe, shell/screenshot, or acceptance_blocked proof cannot accept the ticket. Run the issue-class business assertion.'], requiredEvidence: requiredEvidence }, defaultSupportBusinessProofReadinessFields({
1013
+ artifactPaths: artifactPaths,
1014
+ proofFingerprint: routeOnlyFingerprint,
1015
+ artifactFingerprint: artifactFingerprint,
1016
+ proofFreshness: 'fresh'
1017
+ })), { matchedAssertion: routeOnly });
1018
+ }
1019
+ var passedAssertions = assertions.filter(function (assertion) { return supportBusinessAssertionPassed(assertion.status); });
1020
+ var matched = passedAssertions.find(function (assertion) { return supportBusinessProofAssertionMatchesContract(assertion, gate); });
1021
+ if (!matched) {
1022
+ return __assign({ ready: false, status: 'weak', reason: 'support_business_proof_does_not_match_diagnosis_contract', blockers: ['A passed assertion exists, but it does not map to the diagnosis proof_plan/business_proof_contract.'], requiredEvidence: requiredEvidence }, defaultSupportBusinessProofReadinessFields({ artifactPaths: artifactPaths, artifactFingerprint: artifactFingerprint }));
1023
+ }
1024
+ var proofArtifactPaths = matched.artifactPaths.length ? matched.artifactPaths : artifactPaths;
1025
+ var proofFingerprint = supportBusinessProofFingerprint(gate, matched, proofArtifactPaths);
1026
+ var matchedArtifactFingerprint = supportBusinessProofArtifactFingerprint(proofArtifactPaths);
1027
+ var previousProofFingerprint = cleanText(input.previousProofFingerprint, 160);
1028
+ var previousArtifactFingerprint = cleanText(input.previousArtifactFingerprint, 160);
1029
+ var sameProofAsPrevious = !!previousProofFingerprint && previousProofFingerprint === proofFingerprint;
1030
+ var sameArtifactAsPrevious = !!previousArtifactFingerprint && previousArtifactFingerprint === matchedArtifactFingerprint;
1031
+ if (sameProofAsPrevious || sameArtifactAsPrevious) {
1032
+ return __assign(__assign({ ready: false, status: 'stale', reason: sameProofAsPrevious
1033
+ ? 'support_business_proof_same_fingerprint_as_previous'
1034
+ : 'support_business_proof_same_artifact_fingerprint_as_previous', blockers: ['Business proof did not produce a new proof/artifact fingerprint for this run. Rerun the issue-specific assertion and record fresh artifact proof.'], requiredEvidence: requiredEvidence }, defaultSupportBusinessProofReadinessFields({
1035
+ artifactPaths: proofArtifactPaths,
1036
+ proofFingerprint: proofFingerprint,
1037
+ artifactFingerprint: matchedArtifactFingerprint,
1038
+ proofFreshness: sameProofAsPrevious ? 'same_as_previous' : 'stale_artifact'
1039
+ })), { matchedAssertion: matched });
1040
+ }
1041
+ if (!matched.artifactPaths.length && !artifactPaths.length) {
1042
+ return __assign(__assign({ ready: false, status: 'weak', reason: 'support_business_proof_missing_artifact_path', blockers: ['Business proof must include at least one artifact path.'], requiredEvidence: requiredEvidence }, defaultSupportBusinessProofReadinessFields({
1043
+ artifactPaths: artifactPaths,
1044
+ proofFingerprint: proofFingerprint,
1045
+ artifactFingerprint: matchedArtifactFingerprint
1046
+ })), { matchedAssertion: matched });
1047
+ }
1048
+ var hasDataOrDomProof = !!cleanText(matched.dataProof, 50)
1049
+ || Object.keys(cleanObject(matched.mongoDelta)).length > 0
1050
+ || !!cleanText(matched.observed, 80)
1051
+ || !!cleanText(matched.after, 80);
1052
+ if (!hasDataOrDomProof) {
1053
+ return __assign(__assign({ ready: false, status: 'weak', reason: 'support_business_proof_missing_dom_or_data_proof', blockers: ['Business proof must include DOM/data proof, observed result, after-state, or Mongo delta.'], requiredEvidence: requiredEvidence }, defaultSupportBusinessProofReadinessFields({
1054
+ artifactPaths: proofArtifactPaths,
1055
+ proofFingerprint: proofFingerprint,
1056
+ artifactFingerprint: matchedArtifactFingerprint
1057
+ })), { matchedAssertion: matched });
1058
+ }
1059
+ return __assign(__assign({ ready: true, status: 'passed', reason: 'support_business_proof_ready', blockers: [], requiredEvidence: requiredEvidence }, defaultSupportBusinessProofReadinessFields({
1060
+ artifactPaths: proofArtifactPaths,
1061
+ proofFingerprint: proofFingerprint,
1062
+ artifactFingerprint: matchedArtifactFingerprint,
1063
+ proofFreshness: 'fresh'
1064
+ })), { matchedAssertion: matched });
1065
+ }
591
1066
  function buildSupportClarificationQuestion(gate, blockers) {
592
1067
  if ((gate === null || gate === void 0 ? void 0 : gate.issue_case.reproduction_status) === 'blocked' && gate.issue_case.reproduction_blocker) {
593
1068
  return "Can you provide the missing detail needed to reproduce this issue: ".concat(gate.issue_case.reproduction_blocker, "?");
@@ -603,6 +1078,53 @@ function buildSupportClarificationQuestion(gate, blockers) {
603
1078
  }
604
1079
  return 'Can you send one concrete example record, screen, or action path where this issue still occurs?';
605
1080
  }
1081
+ function buildResolveIOSupportHumanReviewPacket(input) {
1082
+ return {
1083
+ reviewType: input.reviewType,
1084
+ title: cleanText(input.title, 200) || 'Review Support Runner Action',
1085
+ summary: cleanText(input.summary || input.reason, 1000),
1086
+ primaryAction: cleanText(input.primaryAction, 160) || 'review_support_runner_action',
1087
+ question: cleanText(input.question, 1000) || undefined,
1088
+ customerFacingDraftAllowed: input.customerFacingDraftAllowed === true,
1089
+ customerSendAllowed: false,
1090
+ requiresHumanApproval: input.requiresHumanApproval !== false,
1091
+ safety: input.safety || 'internal_hold',
1092
+ reason: cleanText(input.reason, 500),
1093
+ blockers: cleanList(input.blockers, 20, 500),
1094
+ requiredEvidence: cleanList(input.requiredEvidence, 30, 500),
1095
+ evidenceRefs: cleanList(input.evidenceRefs, 40, 500),
1096
+ nextCommands: cleanList(input.nextCommands, 20, 200),
1097
+ forbiddenActions: Array.from(new Set(__spreadArray([
1098
+ 'Do not send customer email without explicit human approval.'
1099
+ ], __read(cleanList(input.forbiddenActions, 20, 500)), false))),
1100
+ costRisk: input.costRisk || 'small_model_or_qa',
1101
+ createdAt: isoNow(input.now)
1102
+ };
1103
+ }
1104
+ function supportAutonomousReviewTypeForAction(action) {
1105
+ switch (action) {
1106
+ case 'run_diagnosis_gate':
1107
+ return 'diagnosis_gate';
1108
+ case 'ask_customer_clarification':
1109
+ return 'customer_clarification';
1110
+ case 'run_owner_scoped_repair':
1111
+ case 'revise_diagnosis_scope':
1112
+ return 'owner_scoped_repair';
1113
+ case 'run_business_proof_qa':
1114
+ return 'business_proof_qa';
1115
+ case 'repair_release_hotfix_first':
1116
+ case 'ready_for_release_gate':
1117
+ return 'release_hotfix';
1118
+ case 'draft_customer_reply':
1119
+ return 'customer_resolution_reply';
1120
+ case 'collect_new_evidence':
1121
+ return 'new_evidence';
1122
+ case 'repair_infra_only':
1123
+ case 'park_manual':
1124
+ default:
1125
+ return 'internal_hold';
1126
+ }
1127
+ }
606
1128
  function decideResolveIOSupportCustomerReplyPolicy(input) {
607
1129
  var _a, _b, _c;
608
1130
  if (input === void 0) { input = {}; }
@@ -612,10 +1134,16 @@ function decideResolveIOSupportCustomerReplyPolicy(input) {
612
1134
  var shouldBlockConfidence = ((_a = input.confidence) === null || _a === void 0 ? void 0 : _a.shouldBlockPr) === true
613
1135
  || ((_b = input.confidence) === null || _b === void 0 ? void 0 : _b.should_block_pr) === true
614
1136
  || ((_c = input.confidence) === null || _c === void 0 ? void 0 : _c.blocked) === true;
615
- var outcomeLabel = cleanText(input.outcomeLabel, 120).toLowerCase();
616
- var businessPassed = supportBusinessAssertionPassed(input.businessAssertionStatus)
617
- || outcomeLabel === 'accepted';
618
- var artifactCount = cleanList(input.businessProofArtifacts, 20, 500).length;
1137
+ var businessProofReadiness = evaluateResolveIOSupportBusinessProofReadiness({
1138
+ diagnosisGate: input.diagnosisGate,
1139
+ outcomeLabel: input.outcomeLabel,
1140
+ businessAssertionStatus: input.businessAssertionStatus,
1141
+ businessAssertions: input.businessAssertions,
1142
+ businessProofArtifacts: input.businessProofArtifacts,
1143
+ previousProofFingerprint: input.previousProofFingerprint,
1144
+ previousArtifactFingerprint: input.previousArtifactFingerprint
1145
+ });
1146
+ var artifactCount = businessProofReadiness.artifactPaths.length;
619
1147
  var unresolvedBlockers = cleanList(input.unresolvedBlockers, 20, 500);
620
1148
  var releaseBlocked = supportReleaseLooksBlocked(input.releaseStatus);
621
1149
  var requiredEvidence = [
@@ -629,6 +1157,7 @@ function decideResolveIOSupportCustomerReplyPolicy(input) {
629
1157
  var canAskCustomer = (gate === null || gate === void 0 ? void 0 : gate.issue_case.reproduction_status) === 'blocked'
630
1158
  || diagnosisValidation.blockers.some(function (blocker) { return /expected_result|observed_result|account_customer_context/.test(blocker); });
631
1159
  if (canAskCustomer) {
1160
+ var clarificationQuestion = buildSupportClarificationQuestion(gate, diagnosisValidation.blockers);
632
1161
  return {
633
1162
  action: 'ask_clarification',
634
1163
  canDraftCustomerReply: true,
@@ -637,7 +1166,22 @@ function decideResolveIOSupportCustomerReplyPolicy(input) {
637
1166
  safety: 'needs_clarification',
638
1167
  reason: 'support_reply_waiting_on_customer_reproduction_detail',
639
1168
  requiredEvidence: requiredEvidence,
640
- clarificationQuestion: buildSupportClarificationQuestion(gate, diagnosisValidation.blockers)
1169
+ clarificationQuestion: clarificationQuestion,
1170
+ humanReviewPacket: buildResolveIOSupportHumanReviewPacket({
1171
+ reviewType: 'customer_clarification',
1172
+ title: 'Review Customer Clarification',
1173
+ summary: 'The runner needs one customer detail before it can reproduce or continue safely.',
1174
+ primaryAction: 'review_customer_clarification',
1175
+ question: clarificationQuestion,
1176
+ customerFacingDraftAllowed: true,
1177
+ safety: 'needs_clarification',
1178
+ reason: 'support_reply_waiting_on_customer_reproduction_detail',
1179
+ blockers: diagnosisValidation.blockers,
1180
+ requiredEvidence: requiredEvidence,
1181
+ nextCommands: ['edit_clarification_question', 'send_after_human_review', 'park_ticket_until_customer_reply'],
1182
+ forbiddenActions: ['Do not run repair from a guessed reproduction path.'],
1183
+ costRisk: 'release_or_customer_send'
1184
+ })
641
1185
  };
642
1186
  }
643
1187
  return {
@@ -647,7 +1191,20 @@ function decideResolveIOSupportCustomerReplyPolicy(input) {
647
1191
  confidenceLevel: confidenceLevel,
648
1192
  safety: 'internal_hold',
649
1193
  reason: 'support_reply_blocked_until_diagnosis_gate_validates',
650
- requiredEvidence: requiredEvidence
1194
+ requiredEvidence: requiredEvidence,
1195
+ humanReviewPacket: buildResolveIOSupportHumanReviewPacket({
1196
+ reviewType: 'internal_hold',
1197
+ title: 'Complete Diagnosis Gate',
1198
+ summary: 'Customer reply is blocked until the diagnosis gate validates.',
1199
+ primaryAction: 'run_support_v5_read_only_diagnosis_gate',
1200
+ safety: 'internal_hold',
1201
+ reason: 'support_reply_blocked_until_diagnosis_gate_validates',
1202
+ blockers: diagnosisValidation.blockers,
1203
+ requiredEvidence: requiredEvidence,
1204
+ nextCommands: ['retrieve_similar_tickets_and_commits', 'run_reproduction_or_classification_probe', 'write_support_diagnosis_gate_json'],
1205
+ forbiddenActions: ['Do not draft a resolution reply before root-cause diagnosis validates.'],
1206
+ costRisk: 'expensive_model'
1207
+ })
651
1208
  };
652
1209
  }
653
1210
  if (shouldBlockConfidence || confidenceLevel !== 'high') {
@@ -658,7 +1215,19 @@ function decideResolveIOSupportCustomerReplyPolicy(input) {
658
1215
  confidenceLevel: confidenceLevel,
659
1216
  safety: 'internal_hold',
660
1217
  reason: shouldBlockConfidence ? 'support_reply_blocked_by_confidence_gate' : 'support_reply_requires_high_confidence',
661
- requiredEvidence: requiredEvidence
1218
+ requiredEvidence: requiredEvidence,
1219
+ humanReviewPacket: buildResolveIOSupportHumanReviewPacket({
1220
+ reviewType: 'internal_hold',
1221
+ title: 'Review Confidence Gate',
1222
+ summary: 'Customer reply is blocked until confidence is high and the confidence gate is not blocking.',
1223
+ primaryAction: 'review_support_confidence_evidence',
1224
+ safety: 'internal_hold',
1225
+ reason: shouldBlockConfidence ? 'support_reply_blocked_by_confidence_gate' : 'support_reply_requires_high_confidence',
1226
+ requiredEvidence: requiredEvidence,
1227
+ nextCommands: ['inspect_confidence_basis', 'collect_missing_business_or_release_evidence'],
1228
+ forbiddenActions: ['Do not draft a customer resolution from medium or low confidence.'],
1229
+ costRisk: 'free_or_deterministic'
1230
+ })
662
1231
  };
663
1232
  }
664
1233
  if (unresolvedBlockers.length) {
@@ -669,7 +1238,20 @@ function decideResolveIOSupportCustomerReplyPolicy(input) {
669
1238
  confidenceLevel: confidenceLevel,
670
1239
  safety: 'internal_hold',
671
1240
  reason: 'support_reply_blocked_by_unresolved_runner_blocker',
672
- requiredEvidence: requiredEvidence
1241
+ requiredEvidence: requiredEvidence,
1242
+ humanReviewPacket: buildResolveIOSupportHumanReviewPacket({
1243
+ reviewType: 'internal_hold',
1244
+ title: 'Resolve Runner Blocker',
1245
+ summary: 'Customer reply is blocked by unresolved runner blockers.',
1246
+ primaryAction: 'review_support_runner_blocker',
1247
+ safety: 'internal_hold',
1248
+ reason: 'support_reply_blocked_by_unresolved_runner_blocker',
1249
+ blockers: unresolvedBlockers,
1250
+ requiredEvidence: requiredEvidence,
1251
+ nextCommands: ['classify_blocker', 'collect_new_evidence_or_repair_smallest_gate'],
1252
+ forbiddenActions: ['Do not send customer status as resolved while blockers remain.'],
1253
+ costRisk: 'small_model_or_qa'
1254
+ })
673
1255
  };
674
1256
  }
675
1257
  if (releaseBlocked) {
@@ -680,18 +1262,49 @@ function decideResolveIOSupportCustomerReplyPolicy(input) {
680
1262
  confidenceLevel: confidenceLevel,
681
1263
  safety: 'internal_hold',
682
1264
  reason: 'support_reply_blocked_until_release_or_hotfix_gate_finishes',
683
- requiredEvidence: requiredEvidence
1265
+ requiredEvidence: requiredEvidence,
1266
+ humanReviewPacket: buildResolveIOSupportHumanReviewPacket({
1267
+ reviewType: 'release_hotfix',
1268
+ title: 'Finish Release Or Hotfix Gate',
1269
+ summary: 'Business proof exists, but the customer reply is blocked until release or hotfix evidence is complete.',
1270
+ primaryAction: 'repair_release_hotfix_first',
1271
+ safety: 'internal_hold',
1272
+ reason: 'support_reply_blocked_until_release_or_hotfix_gate_finishes',
1273
+ blockers: [input.releaseStatus],
1274
+ requiredEvidence: requiredEvidence,
1275
+ nextCommands: ['record_hotfix_evidence', 'commit_and_push_hotfix_to_github', 'rerun_release_gate_once'],
1276
+ forbiddenActions: ['Do not tell the customer the fix is live before release evidence passes.'],
1277
+ costRisk: 'release_or_customer_send'
1278
+ })
684
1279
  };
685
1280
  }
686
- if (!businessPassed) {
1281
+ if (!businessProofReadiness.ready) {
1282
+ var replyReason = businessProofReadiness.reason === 'support_business_proof_route_only_or_acceptance_blocked'
1283
+ ? 'support_reply_rejects_route_only_business_proof'
1284
+ : 'support_reply_requires_business_assertion_pass';
1285
+ var proofRequiredEvidence = Array.from(new Set(__spreadArray(__spreadArray([], __read(requiredEvidence), false), __read(businessProofReadiness.requiredEvidence), false)));
687
1286
  return {
688
1287
  action: 'hold_internal',
689
1288
  canDraftCustomerReply: false,
690
1289
  canSendCustomerReply: false,
691
1290
  confidenceLevel: confidenceLevel,
692
1291
  safety: 'internal_hold',
693
- reason: 'support_reply_requires_business_assertion_pass',
694
- requiredEvidence: requiredEvidence
1292
+ reason: replyReason,
1293
+ requiredEvidence: proofRequiredEvidence,
1294
+ humanReviewPacket: buildResolveIOSupportHumanReviewPacket({
1295
+ reviewType: 'business_proof_qa',
1296
+ title: 'Run Business Proof QA',
1297
+ summary: 'Customer reply is blocked until the issue-specific before/action/after assertion passes.',
1298
+ primaryAction: 'run_support_v5_business_proof_qa_row',
1299
+ safety: 'internal_hold',
1300
+ reason: replyReason,
1301
+ blockers: businessProofReadiness.blockers,
1302
+ requiredEvidence: proofRequiredEvidence,
1303
+ evidenceRefs: businessProofReadiness.artifactPaths,
1304
+ nextCommands: ['execute_issue_class_probe', 'record_before_action_after_artifacts', 'write_aiqa_business_assertion'],
1305
+ forbiddenActions: ['Route probe pass remains route evidence only.'],
1306
+ costRisk: 'small_model_or_qa'
1307
+ })
695
1308
  };
696
1309
  }
697
1310
  if (!(gate === null || gate === void 0 ? void 0 : gate.proof_plan.business_proof_contract) || artifactCount < 1) {
@@ -702,7 +1315,20 @@ function decideResolveIOSupportCustomerReplyPolicy(input) {
702
1315
  confidenceLevel: confidenceLevel,
703
1316
  safety: 'internal_hold',
704
1317
  reason: 'support_reply_requires_business_proof_contract_artifact',
705
- requiredEvidence: requiredEvidence
1318
+ requiredEvidence: requiredEvidence,
1319
+ humanReviewPacket: buildResolveIOSupportHumanReviewPacket({
1320
+ reviewType: 'business_proof_qa',
1321
+ title: 'Attach Business Proof Artifact',
1322
+ summary: 'Customer reply is blocked until the business proof contract and artifact are attached.',
1323
+ primaryAction: 'record_business_proof_artifact',
1324
+ safety: 'internal_hold',
1325
+ reason: 'support_reply_requires_business_proof_contract_artifact',
1326
+ requiredEvidence: requiredEvidence,
1327
+ evidenceRefs: businessProofReadiness.artifactPaths,
1328
+ nextCommands: ['attach_business_proof_contract', 'attach_artifact_path', 'rerun_reply_policy'],
1329
+ forbiddenActions: ['Do not draft a resolution reply without a proof artifact.'],
1330
+ costRisk: 'free_or_deterministic'
1331
+ })
706
1332
  };
707
1333
  }
708
1334
  return {
@@ -713,6 +1339,20 @@ function decideResolveIOSupportCustomerReplyPolicy(input) {
713
1339
  safety: 'safe_to_draft',
714
1340
  reason: 'support_reply_resolution_draft_allowed_after_business_proof',
715
1341
  requiredEvidence: requiredEvidence,
1342
+ humanReviewPacket: buildResolveIOSupportHumanReviewPacket({
1343
+ reviewType: 'customer_resolution_reply',
1344
+ title: 'Review Customer Resolution Reply',
1345
+ summary: "Business proof is ready for ".concat(gate.issue_class, "; draft a customer-facing resolution for human review."),
1346
+ primaryAction: 'review_customer_reply',
1347
+ customerFacingDraftAllowed: true,
1348
+ safety: 'safe_to_draft',
1349
+ reason: 'support_reply_resolution_draft_allowed_after_business_proof',
1350
+ requiredEvidence: requiredEvidence,
1351
+ evidenceRefs: businessProofReadiness.artifactPaths,
1352
+ nextCommands: ['summarize_business_proof', 'draft_customer_reply_for_human_review'],
1353
+ forbiddenActions: ['Draft only; do not send automatically.'],
1354
+ costRisk: 'release_or_customer_send'
1355
+ }),
716
1356
  draftBasis: {
717
1357
  issueClass: gate.issue_class,
718
1358
  businessProof: gate.proof_plan.business_proof_contract.expected_business_state_change,
@@ -721,7 +1361,6 @@ function decideResolveIOSupportCustomerReplyPolicy(input) {
721
1361
  };
722
1362
  }
723
1363
  function buildResolveIOSupportIssueClassProbes(value) {
724
- var _a;
725
1364
  var validation = validateResolveIOSupportDiagnosisGate(value);
726
1365
  var gate = validation.normalized || normalizeResolveIOSupportDiagnosisGate(value);
727
1366
  if (!gate) {
@@ -731,49 +1370,69 @@ function buildResolveIOSupportIssueClassProbes(value) {
731
1370
  var proofContract = gate.proof_plan.business_proof_contract;
732
1371
  var proof = (proofContract === null || proofContract === void 0 ? void 0 : proofContract.expected_business_state_change) || gate.proof_plan.business_assertion;
733
1372
  var assertion = (proofContract === null || proofContract === void 0 ? void 0 : proofContract.data_or_dom_assertion) || gate.proof_plan.data_assertion || gate.proof_plan.after;
734
- var artifacts = ((_a = proofContract === null || proofContract === void 0 ? void 0 : proofContract.proof_artifacts) === null || _a === void 0 ? void 0 : _a.length)
735
- ? " Required artifacts: ".concat(proofContract.proof_artifacts.join(', '), ".")
736
- : '';
1373
+ var contractArtifacts = cleanList(proofContract === null || proofContract === void 0 ? void 0 : proofContract.proof_artifacts, 8, 160);
737
1374
  var common = {
738
1375
  issue_class: gate.issue_class,
739
1376
  probe_type: 'issue_class_probe',
740
1377
  route: route,
1378
+ state_transition: {
1379
+ before: gate.proof_plan.before || gate.proof_plan.before_state_unavailable_reason || (proofContract === null || proofContract === void 0 ? void 0 : proofContract.setup_state) || '',
1380
+ action: gate.proof_plan.action || (proofContract === null || proofContract === void 0 ? void 0 : proofContract.action_under_test) || '',
1381
+ after: gate.proof_plan.after || (proofContract === null || proofContract === void 0 ? void 0 : proofContract.expected_business_state_change) || '',
1382
+ assertion: assertion || gate.proof_plan.business_assertion || ''
1383
+ },
1384
+ acceptance_gate: 'aiqa_business_assertion',
741
1385
  blocks_acceptance_without_business_assertion: true
742
1386
  };
743
1387
  var map = {
744
1388
  no_op_submit: {
745
1389
  action: "Submit the customer action on ".concat(route || 'the affected screen', " and assert a persisted state change or explicit validation message."),
746
- expected: proof || 'Before/action/after proof shows the submit is no longer a no-op.'
1390
+ expected: proof || 'Before/action/after proof shows the submit is no longer a no-op.',
1391
+ failureClass: 'business',
1392
+ requiredArtifacts: ['before form state', 'submit action trace', 'post-submit DOM/data proof', 'method/network result']
747
1393
  },
748
1394
  missing_wrong_data: {
749
1395
  action: "Load the named record/list on ".concat(route || 'the affected route', " and compare visible data to the expected persisted source."),
750
- expected: proof || 'Visible data and persisted data match the customer expectation.'
1396
+ expected: proof || 'Visible data and persisted data match the customer expectation.',
1397
+ failureClass: 'business',
1398
+ requiredArtifacts: ['expected source record', 'visible DOM/data snapshot', 'persisted data comparison']
751
1399
  },
752
1400
  filter_query_mismatch: {
753
1401
  action: 'Apply the reported filter/query inputs and assert the returned rows/counts match the expected dataset.',
754
- expected: proof || 'Filter/query output contains the correct included rows and excludes the wrong rows.'
1402
+ expected: proof || 'Filter/query output contains the correct included rows and excludes the wrong rows.',
1403
+ failureClass: 'business',
1404
+ requiredArtifacts: ['filter input trace', 'included/excluded row proof', 'query or publication result proof']
755
1405
  },
756
1406
  invoice_pdf_export: {
757
1407
  action: 'Generate the invoice/PDF/export from the affected route and inspect the downloaded/generated artifact.',
758
- expected: proof || 'Generated artifact contains the expected customer-visible rows, totals, or fields.'
1408
+ expected: proof || 'Generated artifact contains the expected customer-visible rows, totals, or fields.',
1409
+ failureClass: 'business',
1410
+ requiredArtifacts: ['export trigger trace', 'generated file artifact path', 'parsed artifact content proof']
759
1411
  },
760
1412
  upload_import: {
761
1413
  action: 'Run the upload/import workflow with a representative file and assert parsed plus persisted results.',
762
- expected: proof || 'Import shows a success result and persisted rows/counts changed as expected.'
1414
+ expected: proof || 'Import shows a success result and persisted rows/counts changed as expected.',
1415
+ failureClass: 'business',
1416
+ requiredArtifacts: ['input file fixture', 'import result message', 'persisted row/count delta']
763
1417
  },
764
1418
  route_auth_hydration: {
765
1419
  action: 'Open the route as the affected user and assert authenticated hydration reaches the functional screen, not a shell.',
766
- expected: proof || 'Route hydrates with the required controls/data for the affected account.'
1420
+ expected: proof || 'Route hydrates with the required controls/data for the affected account.',
1421
+ failureClass: 'route',
1422
+ requiredArtifacts: ['auth context', 'hydrated DOM proof', 'console/network error log']
767
1423
  },
768
1424
  slow_query_performance: {
769
1425
  action: 'Run the reported query/workflow with timing/log evidence before and after the fix.',
770
- expected: proof || 'Performance evidence shows the slow path improved without changing results.'
1426
+ expected: proof || 'Performance evidence shows the slow path improved without changing results.',
1427
+ failureClass: 'business',
1428
+ requiredArtifacts: ['before timing', 'after timing', 'result equivalence proof', 'query/log trace']
771
1429
  }
772
1430
  };
773
1431
  var selected = map[gate.issue_class];
774
- return [__assign(__assign({}, common), { objective: "Issue-class probe for ".concat(gate.issue_class, ": ").concat(gate.issue_case.customer_complaint), action: proofContract
1432
+ var requiredArtifacts = Array.from(new Set(__spreadArray(__spreadArray([], __read(contractArtifacts), false), __read(selected.requiredArtifacts), false)));
1433
+ return [__assign(__assign({}, common), { failure_class: selected.failureClass, objective: "Issue-class probe for ".concat(gate.issue_class, ": ").concat(gate.issue_case.customer_complaint), action: proofContract
775
1434
  ? "".concat(proofContract.action_under_test, " ").concat(selected.action)
776
- : selected.action, expected_evidence: "".concat(selected.expected).concat(assertion ? " Assertion: ".concat(assertion, ".") : '').concat(artifacts).trim() })];
1435
+ : selected.action, expected_evidence: "".concat(selected.expected).concat(assertion ? " Assertion: ".concat(assertion, ".") : '').concat(requiredArtifacts.length ? " Required artifacts: ".concat(requiredArtifacts.join(', '), ".") : '').trim(), expected_business_proof: proof || gate.proof_plan.business_assertion, required_artifacts: requiredArtifacts })];
777
1436
  }
778
1437
  function hashResolveIOSupportV5Evidence(value) {
779
1438
  var raw = typeof value === 'string' ? value : JSON.stringify(value || {});
@@ -810,7 +1469,6 @@ function decideResolveIOSupportV5RepeatedFailureStop(input) {
810
1469
  stepType: entry.stepType,
811
1470
  failureClass: entry.failureClass,
812
1471
  blocker: entry.blocker || entry.summary,
813
- blockerFingerprint: entry.blockerFingerprint,
814
1472
  evidenceHash: entry.evidenceHash,
815
1473
  changedFiles: entry.changedFiles,
816
1474
  artifactPaths: entry.artifactPaths,
@@ -823,8 +1481,10 @@ function decideResolveIOSupportV5RepeatedFailureStop(input) {
823
1481
  stepType: latestRecord === null || latestRecord === void 0 ? void 0 : latestRecord.stepType,
824
1482
  failureClass: failureClass,
825
1483
  blocker: input.blocker,
826
- blockerFingerprint: blockerFingerprint,
827
- evidenceHash: evidenceHash
1484
+ evidenceHash: evidenceHash,
1485
+ changedFiles: cleanList(input.changedFiles, 40, 500),
1486
+ artifactPaths: cleanList(input.artifactPaths, 40, 500),
1487
+ summary: input.blocker
828
1488
  },
829
1489
  maxSameFailureRepeats: limit,
830
1490
  maxPingPongTransitions: 3,
@@ -847,17 +1507,39 @@ function decideResolveIOSupportV5RepeatedFailureStop(input) {
847
1507
  failureClass: failureClass,
848
1508
  blockerFingerprint: blockerFingerprint,
849
1509
  evidenceHash: evidenceHash,
1510
+ newEvidence: managerDecision.newEvidence,
1511
+ materialEvidence: managerDecision.materialEvidence,
1512
+ evidenceStrength: managerDecision.evidenceStrength,
1513
+ evidenceSignals: managerDecision.evidenceSignals,
850
1514
  reason: 'support_v5_ping_pong_failure_loop'
851
1515
  };
852
1516
  }
853
- if (managerDecision.action === 'park_repeated_failure' && managerDecision.newEvidence) {
1517
+ if (managerDecision.action === 'park_repeated_failure' && managerDecision.newEvidence && !managerDecision.materialEvidence) {
1518
+ return {
1519
+ shouldStop: true,
1520
+ repeatedCount: managerDecision.sameFailureCount,
1521
+ failureClass: failureClass,
1522
+ blockerFingerprint: blockerFingerprint,
1523
+ evidenceHash: evidenceHash,
1524
+ newEvidence: managerDecision.newEvidence,
1525
+ materialEvidence: managerDecision.materialEvidence,
1526
+ evidenceStrength: managerDecision.evidenceStrength,
1527
+ evidenceSignals: managerDecision.evidenceSignals,
1528
+ reason: 'support_v5_same_failure_with_weak_evidence'
1529
+ };
1530
+ }
1531
+ if (managerDecision.newEvidence && managerDecision.materialEvidence) {
854
1532
  return {
855
1533
  shouldStop: false,
856
1534
  repeatedCount: managerDecision.sameFailureCount,
857
1535
  failureClass: failureClass,
858
1536
  blockerFingerprint: blockerFingerprint,
859
1537
  evidenceHash: evidenceHash,
860
- reason: 'support_v5_retry_allowed_changed_evidence_hash'
1538
+ newEvidence: managerDecision.newEvidence,
1539
+ materialEvidence: managerDecision.materialEvidence,
1540
+ evidenceStrength: managerDecision.evidenceStrength,
1541
+ evidenceSignals: managerDecision.evidenceSignals,
1542
+ reason: 'support_v5_retry_allowed_material_evidence'
861
1543
  };
862
1544
  }
863
1545
  if (managerDecision.action === 'park_repeated_failure') {
@@ -867,6 +1549,10 @@ function decideResolveIOSupportV5RepeatedFailureStop(input) {
867
1549
  failureClass: failureClass,
868
1550
  blockerFingerprint: blockerFingerprint,
869
1551
  evidenceHash: evidenceHash,
1552
+ newEvidence: managerDecision.newEvidence,
1553
+ materialEvidence: managerDecision.materialEvidence,
1554
+ evidenceStrength: managerDecision.evidenceStrength,
1555
+ evidenceSignals: managerDecision.evidenceSignals,
870
1556
  reason: 'support_v5_same_failure_class_without_new_evidence'
871
1557
  };
872
1558
  }
@@ -892,11 +1578,125 @@ function decideResolveIOSupportV5RepeatedFailureStop(input) {
892
1578
  failureClass: failureClass,
893
1579
  blockerFingerprint: blockerFingerprint,
894
1580
  evidenceHash: evidenceHash,
1581
+ newEvidence: managerDecision.newEvidence,
1582
+ materialEvidence: managerDecision.materialEvidence,
1583
+ evidenceStrength: managerDecision.evidenceStrength,
1584
+ evidenceSignals: managerDecision.evidenceSignals,
895
1585
  reason: repeatedCount >= limit
896
1586
  ? 'support_v5_same_failure_class_without_new_evidence'
897
1587
  : 'support_v5_retry_allowed_new_or_below_repeat_limit'
898
1588
  };
899
1589
  }
1590
+ function evaluateResolveIOSupportEvidenceFreshness(input) {
1591
+ var _a;
1592
+ var history = Array.isArray(input.history) ? input.history : [];
1593
+ var latest = history.length ? history[history.length - 1] : undefined;
1594
+ var rawFailureClass = cleanText(input.failureClass || (latest === null || latest === void 0 ? void 0 : latest.failureClass), 80).toLowerCase();
1595
+ var failureClass = rawFailureClass || 'unknown';
1596
+ var blocker = cleanText(input.blocker || (latest === null || latest === void 0 ? void 0 : latest.blocker) || (latest === null || latest === void 0 ? void 0 : latest.summary), 1200);
1597
+ var changedFiles = cleanList(input.changedFiles || (latest === null || latest === void 0 ? void 0 : latest.changedFiles), 40, 500);
1598
+ var artifactPaths = cleanList(input.artifactPaths || (latest === null || latest === void 0 ? void 0 : latest.artifactPaths), 40, 500);
1599
+ var explicitEvidenceHash = cleanText(input.evidenceHash || (latest === null || latest === void 0 ? void 0 : latest.evidenceHash), 120);
1600
+ var evidenceHash = explicitEvidenceHash || hashResolveIOSupportV5Evidence(input.evidence || artifactPaths || blocker || (latest === null || latest === void 0 ? void 0 : latest.summary) || '');
1601
+ var blockerFingerprint = fingerprintResolveIOSupportV5Blocker(blocker || (latest === null || latest === void 0 ? void 0 : latest.summary) || '');
1602
+ var missing = !history.length && !rawFailureClass && !blocker && !explicitEvidenceHash && !artifactPaths.length && !changedFiles.length;
1603
+ if (missing) {
1604
+ return {
1605
+ status: 'missing',
1606
+ failureClass: '',
1607
+ blockerFingerprint: '',
1608
+ evidenceHash: '',
1609
+ sameFailureCount: 0,
1610
+ pingPongCount: 0,
1611
+ newEvidence: false,
1612
+ materialEvidence: false,
1613
+ evidenceStrength: 'none',
1614
+ evidenceSignals: [],
1615
+ loopBudgetShouldReset: false,
1616
+ canRetry: true,
1617
+ mustCollectNewEvidence: false,
1618
+ productRepairFailure: false,
1619
+ reason: 'support_evidence_freshness_waiting_for_first_failure_or_proof',
1620
+ requiredResetEvidence: [
1621
+ 'current blocker fingerprint',
1622
+ 'evidence hash',
1623
+ 'artifact path when available'
1624
+ ],
1625
+ changedFiles: changedFiles,
1626
+ artifactPaths: artifactPaths
1627
+ };
1628
+ }
1629
+ var current = {
1630
+ outcome: 'needs_repair',
1631
+ lane: cleanText(input.lane || (latest === null || latest === void 0 ? void 0 : latest.lane), 80) || (latest === null || latest === void 0 ? void 0 : latest.lane),
1632
+ stepType: cleanText(input.stepType || (latest === null || latest === void 0 ? void 0 : latest.stepType), 80) || (latest === null || latest === void 0 ? void 0 : latest.stepType),
1633
+ failureClass: failureClass,
1634
+ blocker: blocker,
1635
+ evidenceHash: evidenceHash,
1636
+ changedFiles: changedFiles,
1637
+ artifactPaths: artifactPaths,
1638
+ summary: blocker
1639
+ };
1640
+ var policy = (0, ai_runner_manager_policy_1.decideResolveIOAIManagerPolicy)({
1641
+ history: history.map(function (entry) { return ({
1642
+ outcome: entry.outcome,
1643
+ lane: entry.lane,
1644
+ stepType: entry.stepType,
1645
+ failureClass: entry.failureClass,
1646
+ blocker: entry.blocker || entry.summary,
1647
+ evidenceHash: entry.evidenceHash,
1648
+ changedFiles: entry.changedFiles,
1649
+ artifactPaths: entry.artifactPaths,
1650
+ summary: entry.summary,
1651
+ recordedAt: entry.recordedAt
1652
+ }); }),
1653
+ current: current,
1654
+ maxSameFailureRepeats: Math.max(1, Number(input.limit || 2) || 2),
1655
+ maxPingPongTransitions: 3,
1656
+ infraFailureClasses: input.ignoreInfra !== false ? ['infra', 'compile'] : []
1657
+ });
1658
+ var status = 'retry_below_limit';
1659
+ if (policy.action === 'retry_infra') {
1660
+ status = 'infra_ignored';
1661
+ }
1662
+ else if (policy.action === 'park_ping_pong') {
1663
+ status = 'ping_pong';
1664
+ }
1665
+ else if (policy.action === 'park_repeated_failure') {
1666
+ status = policy.newEvidence ? 'weak_evidence' : 'stale_repeated';
1667
+ }
1668
+ else if (policy.newEvidence && policy.materialEvidence) {
1669
+ status = 'material_evidence';
1670
+ }
1671
+ else if (policy.newEvidence && !policy.materialEvidence) {
1672
+ status = 'weak_evidence';
1673
+ }
1674
+ else if (policy.loopBudgetShouldReset || policy.reason === 'manager_policy_new_failure_or_lane') {
1675
+ status = 'fresh';
1676
+ }
1677
+ var mustCollectNewEvidence = policy.action === 'park_repeated_failure'
1678
+ || policy.action === 'park_ping_pong';
1679
+ return {
1680
+ status: status,
1681
+ failureClass: policy.failureClass,
1682
+ blockerFingerprint: blockerFingerprint || policy.blockerFingerprint,
1683
+ evidenceHash: policy.evidenceHash,
1684
+ sameFailureCount: policy.sameFailureCount,
1685
+ pingPongCount: policy.pingPongCount,
1686
+ newEvidence: policy.newEvidence,
1687
+ materialEvidence: policy.materialEvidence,
1688
+ evidenceStrength: policy.evidenceStrength,
1689
+ evidenceSignals: policy.evidenceSignals,
1690
+ loopBudgetShouldReset: policy.loopBudgetShouldReset,
1691
+ canRetry: !mustCollectNewEvidence,
1692
+ mustCollectNewEvidence: mustCollectNewEvidence,
1693
+ productRepairFailure: policy.productRepairFailure,
1694
+ reason: policy.reason,
1695
+ requiredResetEvidence: Array.from(new Set(__spreadArray(__spreadArray([], __read(cleanList(policy.recoveryPlan.loopResetEvidence, 12, 500)), false), __read(cleanList((_a = policy.recoveryAction) === null || _a === void 0 ? void 0 : _a.successCriteria, 12, 500)), false))).slice(0, 18),
1696
+ changedFiles: changedFiles,
1697
+ artifactPaths: artifactPaths
1698
+ };
1699
+ }
900
1700
  function changedFilesOutsideResolveIOSupportDiagnosisOwnerFiles(diagnosisGate, changedFiles, options) {
901
1701
  if (options === void 0) { options = {}; }
902
1702
  var validation = validateResolveIOSupportDiagnosisGate(diagnosisGate);
@@ -934,6 +1734,8 @@ function decideResolveIOSupportV5RepairGate(input) {
934
1734
  blocker: input.blocker,
935
1735
  evidence: input.evidence,
936
1736
  evidenceHash: input.evidenceHash,
1737
+ changedFiles: input.changedFiles,
1738
+ artifactPaths: input.artifactPaths,
937
1739
  limit: Math.max(1, Number(input.maxRepeatedNoProgress || 2) || 2),
938
1740
  ignoreInfra: true
939
1741
  }) : undefined;
@@ -1124,7 +1926,7 @@ function buildResolveIOSupportV5ScopeDigest(input) {
1124
1926
  return raw.slice(0, maxChars);
1125
1927
  }
1126
1928
  function buildResolveIOSupportV5MicrotaskLedger(input) {
1127
- var e_4, _a;
1929
+ var e_7, _a;
1128
1930
  var existing = Array.isArray(input.existing) ? input.existing : [];
1129
1931
  var completedByObjective = new Map();
1130
1932
  try {
@@ -1135,12 +1937,12 @@ function buildResolveIOSupportV5MicrotaskLedger(input) {
1135
1937
  }
1136
1938
  }
1137
1939
  }
1138
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
1940
+ catch (e_7_1) { e_7 = { error: e_7_1 }; }
1139
1941
  finally {
1140
1942
  try {
1141
1943
  if (existing_1_1 && !existing_1_1.done && (_a = existing_1.return)) _a.call(existing_1);
1142
1944
  }
1143
- finally { if (e_4) throw e_4.error; }
1945
+ finally { if (e_7) throw e_7.error; }
1144
1946
  }
1145
1947
  var now = isoNow(input.now);
1146
1948
  var requirements = cleanList(input.requirements, 30, 240);
@@ -1451,6 +2253,8 @@ function decideResolveIOSupportV5Continuation(bundle) {
1451
2253
  failureClass: last.failureClass,
1452
2254
  blocker: last.blocker || last.summary,
1453
2255
  evidenceHash: last.evidenceHash,
2256
+ changedFiles: last.changedFiles,
2257
+ artifactPaths: last.artifactPaths,
1454
2258
  limit: budget.maxRepeatedNoProgress,
1455
2259
  ignoreInfra: true
1456
2260
  }) : null;
@@ -1487,6 +2291,9 @@ function decideResolveIOSupportV5Continuation(bundle) {
1487
2291
  return __assign({ action: 'park', reason: 'support_v5_budget_guard', nextStep: (last === null || last === void 0 ? void 0 : last.stepType) || 'cleanup', repeatedNoProgressCount: repeatedNoProgressCount, budgetExceeded: budgetExceeded }, recoveryFieldsFor(recoveryPlan_5));
1488
2292
  }
1489
2293
  var lastFailureClass = cleanText(last === null || last === void 0 ? void 0 : last.failureClass, 80).toLowerCase();
2294
+ var materialEvidenceRetryAllowed = (repeatedFailure === null || repeatedFailure === void 0 ? void 0 : repeatedFailure.shouldStop) === false
2295
+ && repeatedFailure.newEvidence === true
2296
+ && repeatedFailure.materialEvidence === true;
1490
2297
  if (repeatedNoProgressCount > budget.maxRepeatedNoProgress && /^(infra|compile)$/.test(lastFailureClass)) {
1491
2298
  var recoveryPlan_6 = recoveryPlanFor('retry_infra', 'support_v5_infra_or_compile_repair_required', {
1492
2299
  failureClass: lastFailureClass,
@@ -1494,22 +2301,459 @@ function decideResolveIOSupportV5Continuation(bundle) {
1494
2301
  });
1495
2302
  return __assign({ action: 'continue', reason: 'support_v5_infra_or_compile_repair_required', nextStep: (last === null || last === void 0 ? void 0 : last.stepType) || 'compile_check', repeatedNoProgressCount: repeatedNoProgressCount, budgetExceeded: budgetExceeded }, recoveryFieldsFor(recoveryPlan_6));
1496
2303
  }
1497
- if (repeatedNoProgressCount > budget.maxRepeatedNoProgress) {
1498
- var recoveryPlan_7 = recoveryPlanFor('park_repeated_failure', 'support_v5_repeated_no_progress', {
2304
+ if (repeatedFailure === null || repeatedFailure === void 0 ? void 0 : repeatedFailure.shouldStop) {
2305
+ var recoveryPlan_7 = recoveryPlanFor(repeatedFailure.reason === 'support_v5_ping_pong_failure_loop' ? 'park_ping_pong' : 'park_repeated_failure', repeatedFailure.reason, {
2306
+ failureClass: repeatedFailure.failureClass,
1499
2307
  productRepairFailure: true
1500
2308
  });
1501
- return __assign({ action: 'park', reason: 'support_v5_repeated_no_progress', nextStep: (last === null || last === void 0 ? void 0 : last.stepType) || 'cleanup', repeatedNoProgressCount: repeatedNoProgressCount, budgetExceeded: budgetExceeded }, recoveryFieldsFor(recoveryPlan_7));
2309
+ return __assign({ action: 'park', reason: repeatedFailure.reason, nextStep: (last === null || last === void 0 ? void 0 : last.stepType) || 'cleanup', repeatedNoProgressCount: repeatedFailure.repeatedCount, budgetExceeded: budgetExceeded }, recoveryFieldsFor(recoveryPlan_7));
1502
2310
  }
1503
- if (repeatedFailure === null || repeatedFailure === void 0 ? void 0 : repeatedFailure.shouldStop) {
1504
- var recoveryPlan_8 = recoveryPlanFor(repeatedFailure.reason === 'support_v5_ping_pong_failure_loop' ? 'park_ping_pong' : 'park_repeated_failure', repeatedFailure.reason, {
1505
- failureClass: repeatedFailure.failureClass,
2311
+ if (repeatedNoProgressCount > budget.maxRepeatedNoProgress && !materialEvidenceRetryAllowed) {
2312
+ var recoveryPlan_8 = recoveryPlanFor('park_repeated_failure', 'support_v5_repeated_no_progress', {
1506
2313
  productRepairFailure: true
1507
2314
  });
1508
- return __assign({ action: 'park', reason: repeatedFailure.reason, nextStep: (last === null || last === void 0 ? void 0 : last.stepType) || 'cleanup', repeatedNoProgressCount: repeatedFailure.repeatedCount, budgetExceeded: budgetExceeded }, recoveryFieldsFor(recoveryPlan_8));
2315
+ return __assign({ action: 'park', reason: 'support_v5_repeated_no_progress', nextStep: (last === null || last === void 0 ? void 0 : last.stepType) || 'cleanup', repeatedNoProgressCount: repeatedNoProgressCount, budgetExceeded: budgetExceeded }, recoveryFieldsFor(recoveryPlan_8));
1509
2316
  }
1510
2317
  var recoveryPlan = recoveryPlanFor('continue', 'support_v5_continue');
1511
2318
  return __assign({ action: 'continue', reason: 'support_v5_continue', nextStep: (last === null || last === void 0 ? void 0 : last.stepType) || bundle.supportV5SupervisorState.activeStep, repeatedNoProgressCount: repeatedNoProgressCount, budgetExceeded: false }, recoveryFieldsFor(recoveryPlan));
1512
2319
  }
2320
+ function decideResolveIOSupportV5AutonomousNextAction(input) {
2321
+ var _a, _b, _c, _d, _e;
2322
+ var bundle = input.bundle;
2323
+ var activeMicrotask = selectResolveIOSupportV5ActiveMicrotask(bundle.supportV5MicrotaskLedger || [], bundle.supportV5ActiveMicrotaskId);
2324
+ var diagnosisValidation = validateResolveIOSupportDiagnosisGate(bundle.supportV5DiagnosisGate, {
2325
+ maxOwnerFiles: input.maxOwnerFiles
2326
+ });
2327
+ var activeStepType = cleanText((activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.type) || (!diagnosisValidation.valid ? bundle.supportV5SupervisorState.activeStep : 'cleanup') || 'diagnosis_gate', 80);
2328
+ var repairGate = decideResolveIOSupportV5RepairGate({
2329
+ diagnosisGate: bundle.supportV5DiagnosisGate,
2330
+ activeStepType: activeStepType,
2331
+ changedFiles: input.changedFiles,
2332
+ failureClass: input.failureClass,
2333
+ blocker: input.blocker,
2334
+ evidence: input.evidence,
2335
+ evidenceHash: input.evidenceHash,
2336
+ history: bundle.supportV5StepHistory,
2337
+ artifactPaths: input.artifactPaths,
2338
+ maxOwnerFiles: input.maxOwnerFiles,
2339
+ allowTestsOutsideOwnerFiles: true
2340
+ });
2341
+ var continuation = decideResolveIOSupportV5Continuation(bundle);
2342
+ var customerReplyPolicy = decideResolveIOSupportCustomerReplyPolicy({
2343
+ diagnosisGate: bundle.supportV5DiagnosisGate,
2344
+ outcomeLabel: input.outcomeLabel,
2345
+ confidence: input.confidence,
2346
+ businessAssertionStatus: input.businessAssertionStatus,
2347
+ businessAssertions: input.businessAssertions,
2348
+ businessProofArtifacts: input.businessProofArtifacts,
2349
+ previousProofFingerprint: input.previousProofFingerprint,
2350
+ previousArtifactFingerprint: input.previousArtifactFingerprint,
2351
+ unresolvedBlockers: input.unresolvedBlockers,
2352
+ releaseStatus: input.releaseStatus
2353
+ });
2354
+ var businessProofReadiness = evaluateResolveIOSupportBusinessProofReadiness({
2355
+ diagnosisGate: bundle.supportV5DiagnosisGate,
2356
+ outcomeLabel: input.outcomeLabel,
2357
+ businessAssertionStatus: input.businessAssertionStatus,
2358
+ businessAssertions: input.businessAssertions,
2359
+ businessProofArtifacts: input.businessProofArtifacts,
2360
+ previousProofFingerprint: input.previousProofFingerprint,
2361
+ previousArtifactFingerprint: input.previousArtifactFingerprint
2362
+ });
2363
+ var evidenceFreshness = evaluateResolveIOSupportEvidenceFreshness({
2364
+ history: bundle.supportV5StepHistory,
2365
+ failureClass: input.failureClass,
2366
+ blocker: input.blocker,
2367
+ evidence: input.evidence,
2368
+ evidenceHash: input.evidenceHash,
2369
+ changedFiles: input.changedFiles,
2370
+ artifactPaths: input.artifactPaths || input.businessProofArtifacts,
2371
+ lane: (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.lane) || 'supervisor',
2372
+ stepType: activeStepType,
2373
+ limit: buildResolveIOSupportV5Budget(bundle.supportV5Budget).maxRepeatedNoProgress,
2374
+ ignoreInfra: true
2375
+ });
2376
+ var ownerFiles = ((_a = diagnosisValidation.normalized) === null || _a === void 0 ? void 0 : _a.owner_files) || repairGate.ownerFiles || [];
2377
+ var proofContract = (_b = diagnosisValidation.normalized) === null || _b === void 0 ? void 0 : _b.proof_plan.business_proof_contract;
2378
+ var expectedProof = (proofContract === null || proofContract === void 0 ? void 0 : proofContract.data_or_dom_assertion)
2379
+ || ((_c = diagnosisValidation.normalized) === null || _c === void 0 ? void 0 : _c.proof_plan.business_assertion)
2380
+ || (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.acceptanceProof)
2381
+ || '';
2382
+ var issueClassProbes = diagnosisValidation.valid && diagnosisValidation.normalized
2383
+ ? buildResolveIOSupportIssueClassProbes(diagnosisValidation.normalized)
2384
+ : [];
2385
+ var activeIssueClassProbe = issueClassProbes[0];
2386
+ var issueClassProbeEvidence = activeIssueClassProbe
2387
+ ? Array.from(new Set(__spreadArray([
2388
+ "AIQaBusinessAssertion mapped to ".concat(activeIssueClassProbe.issue_class),
2389
+ "state transition: ".concat(activeIssueClassProbe.state_transition.before || 'before', " -> ").concat(activeIssueClassProbe.state_transition.action || activeIssueClassProbe.action, " -> ").concat(activeIssueClassProbe.state_transition.after || 'after')
2390
+ ], __read(activeIssueClassProbe.required_artifacts.map(function (artifact) { return "artifact: ".concat(artifact); })), false)))
2391
+ : [];
2392
+ var buildRootCauseReadiness = function (action, reason, fields, primaryCommand, nextCommands, blockers) {
2393
+ var _a;
2394
+ var statusByAction = {
2395
+ run_diagnosis_gate: 'diagnosis_required',
2396
+ ask_customer_clarification: 'customer_clarification_required',
2397
+ repair_infra_only: 'infra_repair_only',
2398
+ revise_diagnosis_scope: 'scope_revision_required',
2399
+ run_owner_scoped_repair: 'owner_scoped_repair_ready',
2400
+ run_business_proof_qa: 'business_proof_required',
2401
+ repair_release_hotfix_first: 'release_hotfix_required',
2402
+ collect_new_evidence: 'collect_new_evidence',
2403
+ draft_customer_reply: 'customer_reply_draft_ready',
2404
+ ready_for_release_gate: 'release_gate_ready',
2405
+ park_manual: 'parked'
2406
+ };
2407
+ var nextGateByStatus = {
2408
+ diagnosis_required: 'diagnosis',
2409
+ customer_clarification_required: 'customer_reply',
2410
+ infra_repair_only: 'infra',
2411
+ scope_revision_required: 'scope',
2412
+ owner_scoped_repair_ready: 'repair',
2413
+ business_proof_required: 'business_proof',
2414
+ release_hotfix_required: 'release',
2415
+ release_gate_ready: 'release',
2416
+ customer_reply_draft_ready: 'customer_reply',
2417
+ collect_new_evidence: 'evidence',
2418
+ parked: 'manual'
2419
+ };
2420
+ var status = statusByAction[action] || 'parked';
2421
+ var diagnosisValid = diagnosisValidation.valid === true;
2422
+ var ownerFilesReady = diagnosisValid && ownerFiles.length > 0;
2423
+ var proofPlanReady = diagnosisValid && !!proofContract;
2424
+ var rootCauseFirstSatisfied = diagnosisValid && ownerFilesReady && proofPlanReady;
2425
+ var sameFailureParked = evidenceFreshness.mustCollectNewEvidence === true
2426
+ || (action === 'collect_new_evidence' && /repeated|no_progress|ping_pong|same failure|same evidence/i.test(reason));
2427
+ return {
2428
+ status: status,
2429
+ nextGate: nextGateByStatus[status],
2430
+ nextCommand: primaryCommand || nextCommands[0] || action,
2431
+ rootCauseFirstSatisfied: rootCauseFirstSatisfied,
2432
+ diagnosisValid: diagnosisValid,
2433
+ ownerFilesReady: ownerFilesReady,
2434
+ proofPlanReady: proofPlanReady,
2435
+ businessProofReady: businessProofReadiness.ready === true,
2436
+ infraOnly: action === 'repair_infra_only',
2437
+ sameFailureParked: sameFailureParked,
2438
+ canEditProductCode: fields.canEditProductCode === true && rootCauseFirstSatisfied,
2439
+ canRunIssueClassProbe: rootCauseFirstSatisfied && (action === 'run_business_proof_qa' || status === 'business_proof_required'),
2440
+ canRunBusinessProofQa: rootCauseFirstSatisfied && (action === 'run_business_proof_qa' || !businessProofReadiness.ready),
2441
+ canRelease: action === 'ready_for_release_gate' && businessProofReadiness.ready === true,
2442
+ canDraftCustomerReply: (action === 'draft_customer_reply' && businessProofReadiness.ready === true)
2443
+ || action === 'ask_customer_clarification',
2444
+ requiresHumanDecision: action === 'park_manual' || fields.canRunAutonomously !== true,
2445
+ reason: reason,
2446
+ blockers: blockers,
2447
+ ownerFiles: ownerFiles,
2448
+ issueClass: ((_a = diagnosisValidation.normalized) === null || _a === void 0 ? void 0 : _a.issue_class) || repairGate.issueClass,
2449
+ expectedProof: expectedProof,
2450
+ issueClassProbes: issueClassProbes,
2451
+ businessProofStatus: businessProofReadiness.status,
2452
+ proofFingerprint: businessProofReadiness.proofFingerprint,
2453
+ artifactFingerprint: businessProofReadiness.artifactFingerprint,
2454
+ proofFreshness: businessProofReadiness.proofFreshness
2455
+ };
2456
+ };
2457
+ var makeDecision = function (action, label, reason, fields) {
2458
+ var _a;
2459
+ var primaryCommand = fields.primaryCommand || action;
2460
+ var nextCommands = fields.nextCommands || [primaryCommand];
2461
+ var requiredEvidence = fields.requiredEvidence || [];
2462
+ var blockers = fields.blockers || [];
2463
+ var rootCauseReadiness = buildRootCauseReadiness(action, reason, fields, primaryCommand, nextCommands, blockers);
2464
+ var forbiddenActions = Array.from(new Set(__spreadArray([
2465
+ 'Do not send customer email without explicit human approval.',
2466
+ 'Do not broaden owner_files without revised diagnosis evidence.',
2467
+ 'Do not accept route-load, screenshot-only, scorecard-only, or model-claim proof.'
2468
+ ], __read((fields.forbiddenActions || [])), false)));
2469
+ var humanReviewPacket = fields.humanReviewPacket
2470
+ || (action === 'draft_customer_reply' && customerReplyPolicy.humanReviewPacket ? customerReplyPolicy.humanReviewPacket : undefined)
2471
+ || buildResolveIOSupportHumanReviewPacket({
2472
+ reviewType: supportAutonomousReviewTypeForAction(action),
2473
+ title: label,
2474
+ summary: reason,
2475
+ primaryAction: primaryCommand,
2476
+ customerFacingDraftAllowed: fields.canDraftCustomerReply === true,
2477
+ safety: action === 'draft_customer_reply' ? 'safe_to_draft' : 'internal_hold',
2478
+ reason: reason,
2479
+ blockers: blockers,
2480
+ requiredEvidence: requiredEvidence,
2481
+ evidenceRefs: businessProofReadiness.artifactPaths,
2482
+ nextCommands: nextCommands,
2483
+ forbiddenActions: forbiddenActions,
2484
+ costRisk: fields.canHotfixBackend === true || action === 'draft_customer_reply'
2485
+ ? 'release_or_customer_send'
2486
+ : fields.canRunModel === true
2487
+ ? 'expensive_model'
2488
+ : fields.canRunQa === true
2489
+ ? 'small_model_or_qa'
2490
+ : 'free_or_deterministic',
2491
+ now: input.now
2492
+ });
2493
+ return {
2494
+ action: action,
2495
+ label: label,
2496
+ reason: reason,
2497
+ canRunAutonomously: fields.canRunAutonomously === true,
2498
+ canEditProductCode: fields.canEditProductCode === true,
2499
+ canRunModel: fields.canRunModel === true,
2500
+ canRunQa: fields.canRunQa === true,
2501
+ canHotfixBackend: fields.canHotfixBackend === true,
2502
+ canDraftCustomerReply: fields.canDraftCustomerReply === true,
2503
+ canSendCustomerReply: false,
2504
+ lane: fields.lane || (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.lane) || 'supervisor',
2505
+ stepType: fields.stepType || activeStepType,
2506
+ microtaskId: activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.microtaskId,
2507
+ primaryCommand: primaryCommand,
2508
+ nextCommands: nextCommands,
2509
+ requiredEvidence: requiredEvidence,
2510
+ forbiddenActions: forbiddenActions,
2511
+ blockers: blockers,
2512
+ ownerFiles: ownerFiles,
2513
+ issueClass: ((_a = diagnosisValidation.normalized) === null || _a === void 0 ? void 0 : _a.issue_class) || repairGate.issueClass,
2514
+ expectedProof: expectedProof,
2515
+ issueClassProbes: issueClassProbes,
2516
+ activeMicrotask: activeMicrotask,
2517
+ diagnosisValidation: diagnosisValidation,
2518
+ repairGate: repairGate,
2519
+ continuation: continuation,
2520
+ customerReplyPolicy: customerReplyPolicy,
2521
+ businessProofReadiness: businessProofReadiness,
2522
+ evidenceFreshness: evidenceFreshness,
2523
+ rootCauseReadiness: rootCauseReadiness,
2524
+ humanReviewPacket: humanReviewPacket,
2525
+ hotfixContinuation: fields.hotfixContinuation,
2526
+ recordedAt: isoNow(input.now)
2527
+ };
2528
+ };
2529
+ if (continuation.action === 'park' && continuation.reason === 'support_v5_budget_guard') {
2530
+ return makeDecision('park_manual', 'Park Manual', continuation.reason, {
2531
+ canRunAutonomously: false,
2532
+ lane: 'supervisor',
2533
+ stepType: 'cleanup',
2534
+ primaryCommand: 'park_support_ticket_for_manual_budget_review',
2535
+ requiredEvidence: ['budget summary', 'latest blocker', 'operator decision'],
2536
+ blockers: ['Support V5 budget guard is active.']
2537
+ });
2538
+ }
2539
+ if (continuation.action === 'park') {
2540
+ return makeDecision('collect_new_evidence', 'Collect New Evidence', continuation.reason, {
2541
+ canRunAutonomously: true,
2542
+ canRunModel: false,
2543
+ canRunQa: true,
2544
+ lane: (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.lane) || 'qa',
2545
+ stepType: activeStepType,
2546
+ primaryCommand: 'run_support_v5_recovery_evidence_probe',
2547
+ nextCommands: continuation.recoveryAction.nextCommands,
2548
+ requiredEvidence: continuation.recoveryAction.requiredArtifacts,
2549
+ blockers: [continuation.reason],
2550
+ forbiddenActions: ['Do not run another product-code repair until blockerFingerprint or evidenceHash changes.']
2551
+ });
2552
+ }
2553
+ if (customerReplyPolicy.action === 'ask_clarification') {
2554
+ return makeDecision('ask_customer_clarification', 'Ask Customer Clarification', customerReplyPolicy.reason, {
2555
+ canRunAutonomously: false,
2556
+ canRunModel: false,
2557
+ canEditProductCode: false,
2558
+ canDraftCustomerReply: true,
2559
+ lane: 'customer',
2560
+ stepType: 'customer_reply',
2561
+ primaryCommand: ((_d = customerReplyPolicy.humanReviewPacket) === null || _d === void 0 ? void 0 : _d.primaryAction) || 'review_customer_clarification',
2562
+ nextCommands: ((_e = customerReplyPolicy.humanReviewPacket) === null || _e === void 0 ? void 0 : _e.nextCommands) || ['edit_clarification_question', 'send_after_human_review', 'park_ticket_until_customer_reply'],
2563
+ requiredEvidence: customerReplyPolicy.requiredEvidence,
2564
+ blockers: diagnosisValidation.blockers,
2565
+ forbiddenActions: [
2566
+ 'Do not run repair from a guessed reproduction path.',
2567
+ 'Do not send customer email without explicit human approval.'
2568
+ ],
2569
+ humanReviewPacket: customerReplyPolicy.humanReviewPacket
2570
+ });
2571
+ }
2572
+ if (repairGate.action === 'diagnose_only' || (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.type) === 'diagnosis_gate' || !diagnosisValidation.valid) {
2573
+ return makeDecision('run_diagnosis_gate', 'Run Diagnosis Gate', 'support_v5_root_cause_first_required', {
2574
+ canRunAutonomously: true,
2575
+ canRunModel: true,
2576
+ canEditProductCode: false,
2577
+ lane: 'build',
2578
+ stepType: 'diagnosis_gate',
2579
+ primaryCommand: 'run_support_v5_read_only_diagnosis_gate',
2580
+ nextCommands: ['retrieve_similar_tickets_and_commits', 'run_reproduction_or_classification_probe', 'write_support_diagnosis_gate_json'],
2581
+ requiredEvidence: [
2582
+ 'issue_case expected/observed/account context',
2583
+ 'accepted falsifiable hypothesis',
2584
+ 'rejected alternatives',
2585
+ 'failing path',
2586
+ 'small owner_files set',
2587
+ 'before/action/after business proof plan'
2588
+ ],
2589
+ blockers: repairGate.blockers,
2590
+ forbiddenActions: ['No source edits during diagnosis.']
2591
+ });
2592
+ }
2593
+ if (repairGate.action === 'infra_repair_only') {
2594
+ return makeDecision('repair_infra_only', 'Repair Infra Only', 'support_v5_infra_failure_before_product_repair', {
2595
+ canRunAutonomously: true,
2596
+ canRunModel: false,
2597
+ canEditProductCode: false,
2598
+ canRunQa: true,
2599
+ lane: 'qa',
2600
+ stepType: activeStepType,
2601
+ primaryCommand: 'run_support_v5_infra_repair',
2602
+ nextCommands: ['rerun_puppeteer_compile_startup_preflight', 'repair_harness_or_cache_only', 'record_infra_artifact'],
2603
+ requiredEvidence: ['preflight log', 'compile/startup/browser status', 'new infra blocker hash or pass'],
2604
+ blockers: repairGate.blockers,
2605
+ forbiddenActions: ['Do not charge infra failures as product-code repair failures.']
2606
+ });
2607
+ }
2608
+ if (repairGate.action === 'reject_out_of_scope') {
2609
+ return makeDecision('revise_diagnosis_scope', 'Revise Diagnosis Scope', 'support_v5_owner_scope_block', {
2610
+ canRunAutonomously: true,
2611
+ canRunModel: true,
2612
+ canEditProductCode: false,
2613
+ lane: 'build',
2614
+ stepType: 'diagnosis_gate',
2615
+ primaryCommand: 'revise_support_diagnosis_gate_with_new_owner_file_evidence',
2616
+ nextCommands: ['attach_out_of_scope_diff', 'prove_new_owner_file_is_required', 'update_support_diagnosis_gate'],
2617
+ requiredEvidence: ['new root-cause evidence for each added owner file'],
2618
+ blockers: repairGate.blockers,
2619
+ forbiddenActions: ['Do not edit files outside owner_files before diagnosis is revised.']
2620
+ });
2621
+ }
2622
+ if (repairGate.action === 'park_repeated_failure') {
2623
+ return makeDecision('collect_new_evidence', 'Collect New Evidence', 'support_v5_repeated_failure_needs_new_evidence', {
2624
+ canRunAutonomously: true,
2625
+ canRunModel: false,
2626
+ canRunQa: true,
2627
+ lane: (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.lane) || 'qa',
2628
+ stepType: activeStepType,
2629
+ primaryCommand: 'run_support_v5_recovery_evidence_probe',
2630
+ nextCommands: repairGate.recoveryAction.nextCommands,
2631
+ requiredEvidence: repairGate.recoveryAction.requiredArtifacts,
2632
+ blockers: repairGate.blockers,
2633
+ forbiddenActions: ['Do not run another repair loop until new material evidence exists.']
2634
+ });
2635
+ }
2636
+ if (supportReleaseLooksBlocked(input.releaseStatus)) {
2637
+ var releaseBlocker = cleanList(input.unresolvedBlockers, 20, 500).join('; ')
2638
+ || cleanText(input.blocker || input.releaseStatus, 1000)
2639
+ || 'Support release is blocked.';
2640
+ var hotfixContinuation = (0, ai_runner_manager_policy_1.decideResolveIOAIManagerHotfixContinuation)({
2641
+ evidence: input.hotfixEvidence,
2642
+ policy: input.releasePolicy,
2643
+ releaseGatePassed: input.releaseGatePassed,
2644
+ failureClass: 'release',
2645
+ blocker: releaseBlocker,
2646
+ now: input.now
2647
+ });
2648
+ var hotfixPrimaryCommandByAction = {
2649
+ record_hotfix_evidence: 'record_hotfix_evidence',
2650
+ request_force_deploy_reason: 'request_force_deploy_reason',
2651
+ rerun_release_gate: 'rerun_support_release_gate_once',
2652
+ continue_runner: 'continue_support_runner_after_committed_hotfix',
2653
+ allow_one_full_deploy: 'execute_one_full_deploy_with_force_evidence',
2654
+ park_manual: 'park_support_release_manual'
2655
+ };
2656
+ var hotfixNextCommands = Array.from(new Set(__spreadArray(__spreadArray([
2657
+ 'classify_release_blocker',
2658
+ 'prepare_hotfix_patch_without_live_apply',
2659
+ 'commit_and_push_hotfix_to_github',
2660
+ 'record_github_commit_for_hotfix'
2661
+ ], __read(hotfixContinuation.nextCommands), false), [
2662
+ 'apply_backend_hotfix_only_after_commit_proof',
2663
+ 'rerun_release_gate_once'
2664
+ ], false)));
2665
+ var hotfixRequiredEvidence = Array.from(new Set(__spreadArray([
2666
+ 'hotfix evidence',
2667
+ 'full sourceCommitSha, githubCommitUrl, and passed gitPushStatus for the exact pushed GitHub commit',
2668
+ 'checksum before/after',
2669
+ 'health/self-test pass',
2670
+ 'release gate result'
2671
+ ], __read(hotfixContinuation.requiredEvidence), false)));
2672
+ var hotfixForbiddenActions = [
2673
+ 'Do not apply a live hotfix before the exact diff is committed and pushed to GitHub.',
2674
+ 'Do not mark a hotfix durable without sourceCommitSha, githubCommitUrl, and passed gitPushStatus.',
2675
+ 'Do not run a full deploy to clear a duplicate release loop unless force evidence explicitly allows one.'
2676
+ ];
2677
+ return makeDecision('repair_release_hotfix_first', 'Hotfix Release', 'support_v5_release_blocked_hotfix_first', {
2678
+ canRunAutonomously: hotfixContinuation.action !== 'park_manual',
2679
+ canRunModel: false,
2680
+ canEditProductCode: false,
2681
+ canHotfixBackend: hotfixContinuation.action !== 'park_manual',
2682
+ lane: 'release',
2683
+ stepType: 'release_gate',
2684
+ primaryCommand: hotfixPrimaryCommandByAction[hotfixContinuation.action] || 'record_hotfix_evidence',
2685
+ nextCommands: hotfixNextCommands,
2686
+ requiredEvidence: hotfixRequiredEvidence,
2687
+ blockers: Array.from(new Set(__spreadArray(__spreadArray([], __read(cleanList(input.unresolvedBlockers, 20, 500)), false), __read(hotfixContinuation.blockers), false))),
2688
+ forbiddenActions: hotfixForbiddenActions,
2689
+ hotfixContinuation: hotfixContinuation
2690
+ });
2691
+ }
2692
+ if ((activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.lane) === 'qa' || /^(qa_row|qa_retest|business_proof|route_probe|issue_class_probe)$/.test(activeStepType)) {
2693
+ return makeDecision('run_business_proof_qa', 'Run Business Proof QA', 'support_v5_business_assertion_required', {
2694
+ canRunAutonomously: true,
2695
+ canRunQa: true,
2696
+ canRunModel: false,
2697
+ canEditProductCode: false,
2698
+ lane: 'qa',
2699
+ stepType: /^(qa_row|qa_retest|business_proof|route_probe|issue_class_probe)$/.test(activeStepType) ? activeStepType : 'qa_row',
2700
+ primaryCommand: 'run_support_v5_business_proof_qa_row',
2701
+ nextCommands: ['start_local_stack_if_needed', 'execute_issue_class_probe', 'record_before_action_after_artifacts', 'write_aiqa_business_assertion'],
2702
+ requiredEvidence: Array.from(new Set(__spreadArray(['AIQaBusinessAssertion pass', 'DOM/data proof', 'artifact path', 'Mongo delta when data-changing'], __read(issueClassProbeEvidence), false))),
2703
+ forbiddenActions: ['Route probe pass alone remains route evidence only.']
2704
+ });
2705
+ }
2706
+ if (!activeMicrotask && customerReplyPolicy.action === 'draft_resolution_reply') {
2707
+ return makeDecision('draft_customer_reply', 'Draft Customer Reply', customerReplyPolicy.reason, {
2708
+ canRunAutonomously: true,
2709
+ canRunModel: true,
2710
+ canDraftCustomerReply: true,
2711
+ lane: 'customer',
2712
+ stepType: 'customer_reply',
2713
+ primaryCommand: 'draft_support_customer_resolution_reply',
2714
+ nextCommands: ['summarize_business_proof', 'draft_customer_reply_for_human_review'],
2715
+ requiredEvidence: customerReplyPolicy.requiredEvidence,
2716
+ forbiddenActions: ['Draft only; do not send.']
2717
+ });
2718
+ }
2719
+ if (!activeMicrotask && diagnosisValidation.valid && !businessProofReadiness.ready) {
2720
+ return makeDecision('run_business_proof_qa', 'Run Business Proof QA', businessProofReadiness.reason, {
2721
+ canRunAutonomously: true,
2722
+ canRunQa: true,
2723
+ canRunModel: false,
2724
+ canEditProductCode: false,
2725
+ lane: 'qa',
2726
+ stepType: 'business_proof',
2727
+ primaryCommand: 'run_support_v5_business_proof_qa_row',
2728
+ nextCommands: ['execute_issue_class_probe', 'record_before_action_after_artifacts', 'write_aiqa_business_assertion'],
2729
+ requiredEvidence: Array.from(new Set(__spreadArray(__spreadArray([], __read(businessProofReadiness.requiredEvidence), false), __read(issueClassProbeEvidence), false))),
2730
+ blockers: businessProofReadiness.blockers,
2731
+ forbiddenActions: ['Do not run release or customer reply until businessProofReadiness.ready=true.']
2732
+ });
2733
+ }
2734
+ if (!activeMicrotask && businessProofReadiness.ready) {
2735
+ return makeDecision('ready_for_release_gate', 'Run Release Gate', 'support_v5_business_proof_complete_release_gate_ready', {
2736
+ canRunAutonomously: true,
2737
+ canRunQa: true,
2738
+ lane: 'release',
2739
+ stepType: 'release_gate',
2740
+ primaryCommand: 'run_support_release_gate_once',
2741
+ nextCommands: ['verify_compile_and_business_proof_artifacts', 'run_release_gate_once', 'record_release_status'],
2742
+ requiredEvidence: ['compile pass', 'business assertion artifact', 'release status']
2743
+ });
2744
+ }
2745
+ return makeDecision('run_owner_scoped_repair', 'Run Owner-Scoped Repair', 'support_v5_product_repair_allowed_after_diagnosis', {
2746
+ canRunAutonomously: true,
2747
+ canRunModel: true,
2748
+ canEditProductCode: true,
2749
+ lane: (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.lane) || 'build',
2750
+ stepType: activeStepType || 'build_repair',
2751
+ primaryCommand: 'run_support_v5_owner_scoped_repair',
2752
+ nextCommands: ['load_owner_files_only', 'apply_smallest_fix', 'run_smallest_compile_or_unit_gate', 'handoff_to_business_proof_qa'],
2753
+ requiredEvidence: ['changed files within owner_files', 'compile/unit proof', 'next QA row'],
2754
+ forbiddenActions: ['Do not edit outside owner_files unless diagnosis is revised with new evidence.']
2755
+ });
2756
+ }
1513
2757
  function buildResolveIOSupportV5DiagnoseFirstPrompt(lines) {
1514
2758
  var _a, _b;
1515
2759
  return [
@@ -1533,7 +2777,7 @@ function buildResolveIOSupportV5DiagnoseFirstPrompt(lines) {
1533
2777
  ].filter(Boolean);
1534
2778
  }
1535
2779
  function buildResolveIOSupportV5MicrotaskPrompt(input) {
1536
- var _a, _b, _c, _d, _e, _f;
2780
+ var _a, _b, _c, _d, _e, _f, _g;
1537
2781
  var activeMicrotask = selectResolveIOSupportV5ActiveMicrotask(input.bundle.supportV5MicrotaskLedger || [], input.bundle.supportV5ActiveMicrotaskId);
1538
2782
  var diagnosisValidation = validateResolveIOSupportDiagnosisGate(input.bundle.supportV5DiagnosisGate);
1539
2783
  var diagnosisGate = diagnosisValidation.normalized || input.bundle.supportV5DiagnosisGate;
@@ -1556,6 +2800,39 @@ function buildResolveIOSupportV5MicrotaskPrompt(input) {
1556
2800
  var artifactPaths = cleanList(((_b = input.artifactPaths) === null || _b === void 0 ? void 0 : _b.length) ? input.artifactPaths : laneMemory.artifactPaths, 8, 200);
1557
2801
  var targetFiles = cleanList(((_c = input.targetFiles) === null || _c === void 0 ? void 0 : _c.length) ? input.targetFiles : activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.targetFiles, 5, 160);
1558
2802
  var contextSnippets = cleanList(input.contextSnippets, 5, 360);
2803
+ var similarCaseSelection = Array.isArray(input.similarCaseHints)
2804
+ ? selectResolveIOSupportSimilarCaseHints({
2805
+ candidates: input.similarCaseHints,
2806
+ issueClass: diagnosisGate === null || diagnosisGate === void 0 ? void 0 : diagnosisGate.issue_class,
2807
+ ownerFiles: diagnosisGate === null || diagnosisGate === void 0 ? void 0 : diagnosisGate.owner_files,
2808
+ text: input.bundle.supportV5ScopeDigest || input.bundle.supportV5SupervisorState.currentGoal,
2809
+ limit: 5
2810
+ })
2811
+ : input.similarCaseHints && typeof input.similarCaseHints === 'object'
2812
+ ? {
2813
+ ranked: cleanObject(input.similarCaseHints).ranked || [],
2814
+ similarTickets: cleanObject(input.similarCaseHints).similarTickets || cleanObject(input.similarCaseHints).similar_tickets || [],
2815
+ similarCommits: cleanObject(input.similarCaseHints).similarCommits || cleanObject(input.similarCaseHints).similar_commits || [],
2816
+ ignoredCount: Number(cleanObject(input.similarCaseHints).ignoredCount || cleanObject(input.similarCaseHints).ignored_count || 0),
2817
+ generatedAt: cleanText(cleanObject(input.similarCaseHints).generatedAt || cleanObject(input.similarCaseHints).generated_at, 120)
2818
+ }
2819
+ : undefined;
2820
+ var similarCaseHintsText = ((_d = similarCaseSelection === null || similarCaseSelection === void 0 ? void 0 : similarCaseSelection.ranked) === null || _d === void 0 ? void 0 : _d.length)
2821
+ ? __spreadArray([
2822
+ 'Similar accepted fix hints. Advisory only: use these to prioritize inspection paths, not as proof.'
2823
+ ], __read(similarCaseSelection.ranked.slice(0, 5).map(function (hint, index) {
2824
+ var _a;
2825
+ return [
2826
+ "".concat(index + 1, ". source=").concat(hint.source || 'unknown', " score=").concat(Number(hint.score || 0)),
2827
+ hint.ticketNumber ? "ticket=".concat(hint.ticketNumber) : '',
2828
+ hint.commitSha ? "commit=".concat(hint.commitSha) : '',
2829
+ hint.issueClass ? "issue_class=".concat(hint.issueClass) : '',
2830
+ ((_a = hint.ownerFiles) === null || _a === void 0 ? void 0 : _a.length) ? "owner_files=".concat(hint.ownerFiles.slice(0, 4).join(', ')) : '',
2831
+ hint.reason ? "signals=".concat(hint.reason) : '',
2832
+ hint.title ? "title=".concat(cleanText(hint.title, 180)) : ''
2833
+ ].filter(Boolean).join(' | ');
2834
+ })), false).join('\n')
2835
+ : '';
1559
2836
  var qaRow = input.activeQaRow || (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.lane) === 'qa'
1560
2837
  ? input.activeQaRow || laneMemory.activeQaRow || input.bundle.supportV5SupervisorState.currentQaRow
1561
2838
  : undefined;
@@ -1597,11 +2874,15 @@ function buildResolveIOSupportV5MicrotaskPrompt(input) {
1597
2874
  "Owner files: ".concat(diagnosisGate.owner_files.join(', ')),
1598
2875
  "Business proof required: ".concat(diagnosisGate.proof_plan.business_assertion),
1599
2876
  diagnosisGate.proof_plan.business_proof_contract
1600
- ? "Business proof contract: ".concat((_d = diagnosisGate.proof_plan.business_proof_contract) === null || _d === void 0 ? void 0 : _d.action_under_test, " -> ").concat((_e = diagnosisGate.proof_plan.business_proof_contract) === null || _e === void 0 ? void 0 : _e.expected_business_state_change, "; assertion ").concat((_f = diagnosisGate.proof_plan.business_proof_contract) === null || _f === void 0 ? void 0 : _f.data_or_dom_assertion)
2877
+ ? "Business proof contract: ".concat((_e = diagnosisGate.proof_plan.business_proof_contract) === null || _e === void 0 ? void 0 : _e.action_under_test, " -> ").concat((_f = diagnosisGate.proof_plan.business_proof_contract) === null || _f === void 0 ? void 0 : _f.expected_business_state_change, "; assertion ").concat((_g = diagnosisGate.proof_plan.business_proof_contract) === null || _g === void 0 ? void 0 : _g.data_or_dom_assertion)
1601
2878
  : '',
1602
2879
  "Before/action/after: ".concat(diagnosisGate.proof_plan.before || diagnosisGate.proof_plan.before_state_unavailable_reason, " -> ").concat(diagnosisGate.proof_plan.action, " -> ").concat(diagnosisGate.proof_plan.after)
1603
2880
  ].filter(Boolean).join('\n') : 'SupportDiagnosisGate is not valid. Park instead of editing product code.'
1604
2881
  },
2882
+ diagnosisActive && similarCaseHintsText ? {
2883
+ name: 'similar_accepted_fix_hints',
2884
+ text: similarCaseHintsText
2885
+ } : undefined,
1605
2886
  {
1606
2887
  name: 'scope_digest',
1607
2888
  text: cleanText(input.bundle.supportV5ScopeDigest || input.bundle.supportV5SupervisorState.approvedScope, 900)
@@ -1647,6 +2928,7 @@ function buildResolveIOSupportV5MicrotaskPrompt(input) {
1647
2928
  'Launch Puppeteer from `PUPPETEER_EXECUTABLE_PATH || CHROME_BIN`, seed localStorage from `qa-artifacts/auth-bootstrap-storage-state.json`, then navigate to the active QA route.',
1648
2929
  'Before passing, confirm `qa-artifacts/auth-bootstrap-result.json` used the ticket reporter or named affected user when available. If it used generic admin/dev while `qa-live-data-seed-result.json.selected.qa_user_context` names a reporter/affected user, rerun auth as that user or return needs-fix.',
1649
2930
  'Drive the visible customer workflow for this one row. Capture a new customer-facing screenshot/caption and update `qa-artifacts/qa-coverage-matrix.json` with workflow, route, data id/name, assertion, screenshot path, caption, and pass/failed/blocked status.',
2931
+ 'Also write `qa-artifacts/aiqa-business-assertion.json` with one AIQaBusinessAssertion object: assertion, status, workflow, route, before, action, expected, after/observed, dataProof or mongoDelta, artifactPaths, and metadata.supportDiagnosisProof=true only when it maps to the active SupportDiagnosisGate proof_plan.',
1650
2932
  'After selecting any From/To, source/target, dropdown, combobox, rio-select, filter, item, customer, yard, chemical, or treatment-plan value, read the visible control text back from the DOM. If it still contains placeholder text such as Select Chemical, Select Yard, Select Customer, Select Treatment Plan Type, Loading..., empty, null, or undefined, do not click the action button and do not mark pass. Capture the selected-state blocker screenshot/DOM text and return needs-fix.',
1651
2933
  'If the row needs persisted data proof, create that proof yourself in the same bounded QA command by querying localhost QA Mongo through process.env.MONGO_URL after the visible UI action. Write the result under qa-artifacts/ as JSON and reference that path in the matrix. Do not ask for a missing post-action DB artifact while the local QA stack is running; either write it or return needs-fix with the exact query/script error. For update-interchangeables rows, the JSON must include concrete non-placeholder fromText and toText, before/after counts or sample documents for treatment plans and tank/interchangeable records, and must fail if either selected value is only an arrow/placeholder or if the persisted collections are empty.',
1652
2934
  'If the row names multiple concrete entities such as assets, units, BOLs, invoices, chemicals, customers, yards, or numbered records, prove every named entity. Do not pass by proving only one representative record.',
@@ -1666,7 +2948,7 @@ function buildResolveIOSupportV5MicrotaskPrompt(input) {
1666
2948
  ? 'Return strict JSON only: {"status":"pass"|"needs-fix"|"blocked","microtaskId":"","summary":"","evidence":[""],"artifacts":[""],"next_actions":[""]}.'
1667
2949
  : 'Return concise Markdown with: Microtask Result, Root Cause, Changes, Self-Gate, Acceptance Proof, Residual Risk.'
1668
2950
  }
1669
- ].filter(function (section) { return cleanText(section.text, 20); });
2951
+ ].filter(function (section) { return !!section && !!cleanText(section.text, 20); });
1670
2952
  var promptSections = sections.map(function (section) { return ({
1671
2953
  name: section.name,
1672
2954
  tokenEstimate: estimateTextTokens(section.text)
@@ -1690,7 +2972,7 @@ function buildResolveIOSupportV5MicrotaskPrompt(input) {
1690
2972
  };
1691
2973
  }
1692
2974
  function summarizeResolveIOSupportV5MicrotaskUsage(bundle) {
1693
- var e_5, _a, e_6, _b;
2975
+ var e_8, _a, e_9, _b;
1694
2976
  var byMicrotask = new Map();
1695
2977
  var bySection = new Map();
1696
2978
  var totalPromptTokenEstimate = 0;
@@ -1705,17 +2987,17 @@ function summarizeResolveIOSupportV5MicrotaskUsage(bundle) {
1705
2987
  existing.calls += 1;
1706
2988
  byMicrotask.set(usage.microtaskId, existing);
1707
2989
  try {
1708
- for (var _e = (e_6 = void 0, __values(usage.promptSections || [])), _f = _e.next(); !_f.done; _f = _e.next()) {
2990
+ for (var _e = (e_9 = void 0, __values(usage.promptSections || [])), _f = _e.next(); !_f.done; _f = _e.next()) {
1709
2991
  var section = _f.value;
1710
2992
  bySection.set(section.name, (bySection.get(section.name) || 0) + section.tokenEstimate);
1711
2993
  }
1712
2994
  }
1713
- catch (e_6_1) { e_6 = { error: e_6_1 }; }
2995
+ catch (e_9_1) { e_9 = { error: e_9_1 }; }
1714
2996
  finally {
1715
2997
  try {
1716
2998
  if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
1717
2999
  }
1718
- finally { if (e_6) throw e_6.error; }
3000
+ finally { if (e_9) throw e_9.error; }
1719
3001
  }
1720
3002
  var hardCap = usage.lane === 'qa' ? promptBudget.qaMicrotaskHardCap : promptBudget.buildMicrotaskHardCap;
1721
3003
  if ((usage.promptTokenEstimate || 0) > hardCap) {
@@ -1723,12 +3005,12 @@ function summarizeResolveIOSupportV5MicrotaskUsage(bundle) {
1723
3005
  }
1724
3006
  }
1725
3007
  }
1726
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
3008
+ catch (e_8_1) { e_8 = { error: e_8_1 }; }
1727
3009
  finally {
1728
3010
  try {
1729
3011
  if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
1730
3012
  }
1731
- finally { if (e_5) throw e_5.error; }
3013
+ finally { if (e_8) throw e_8.error; }
1732
3014
  }
1733
3015
  return {
1734
3016
  totalPromptTokenEstimate: totalPromptTokenEstimate,