@resolveio/server-lib 22.3.127 → 22.3.129

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,6 +47,14 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
47
47
  return to.concat(ar || Array.prototype.slice.call(from));
48
48
  };
49
49
  Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.normalizeResolveIOSupportDiagnosisGate = normalizeResolveIOSupportDiagnosisGate;
51
+ exports.extractResolveIOSupportDiagnosisGateFromText = extractResolveIOSupportDiagnosisGateFromText;
52
+ exports.validateResolveIOSupportDiagnosisGate = validateResolveIOSupportDiagnosisGate;
53
+ exports.buildResolveIOSupportIssueClassProbes = buildResolveIOSupportIssueClassProbes;
54
+ exports.hashResolveIOSupportV5Evidence = hashResolveIOSupportV5Evidence;
55
+ exports.decideResolveIOSupportV5RepeatedFailureStop = decideResolveIOSupportV5RepeatedFailureStop;
56
+ exports.changedFilesOutsideResolveIOSupportDiagnosisOwnerFiles = changedFilesOutsideResolveIOSupportDiagnosisOwnerFiles;
57
+ exports.applyResolveIOSupportDiagnosisGateToMicrotasks = applyResolveIOSupportDiagnosisGateToMicrotasks;
50
58
  exports.fingerprintResolveIOSupportV5Blocker = fingerprintResolveIOSupportV5Blocker;
51
59
  exports.buildResolveIOSupportV5Budget = buildResolveIOSupportV5Budget;
52
60
  exports.buildResolveIOSupportV5PromptBudget = buildResolveIOSupportV5PromptBudget;
@@ -61,6 +69,7 @@ exports.buildResolveIOSupportV5DiagnoseFirstPrompt = buildResolveIOSupportV5Diag
61
69
  exports.buildResolveIOSupportV5MicrotaskPrompt = buildResolveIOSupportV5MicrotaskPrompt;
62
70
  exports.summarizeResolveIOSupportV5MicrotaskUsage = summarizeResolveIOSupportV5MicrotaskUsage;
63
71
  exports.buildResolveIOSupportV5Incident = buildResolveIOSupportV5Incident;
72
+ var ai_runner_manager_policy_1 = require("./ai-runner-manager-policy");
64
73
  function isoNow(value) {
65
74
  if (value instanceof Date) {
66
75
  return value.toISOString();
@@ -104,6 +113,518 @@ function cleanList(values, limit, max) {
104
113
  }
105
114
  return result;
106
115
  }
116
+ function cleanObject(value) {
117
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
118
+ }
119
+ function pickText(source, fields, max) {
120
+ var e_2, _a;
121
+ if (max === void 0) { max = 1000; }
122
+ try {
123
+ for (var fields_1 = __values(fields), fields_1_1 = fields_1.next(); !fields_1_1.done; fields_1_1 = fields_1.next()) {
124
+ var field = fields_1_1.value;
125
+ var normalized = cleanText(source === null || source === void 0 ? void 0 : source[field], max);
126
+ if (normalized) {
127
+ return normalized;
128
+ }
129
+ }
130
+ }
131
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
132
+ finally {
133
+ try {
134
+ if (fields_1_1 && !fields_1_1.done && (_a = fields_1.return)) _a.call(fields_1);
135
+ }
136
+ finally { if (e_2) throw e_2.error; }
137
+ }
138
+ return '';
139
+ }
140
+ function normalizeIssueClass(value) {
141
+ var normalized = cleanText(value, 80)
142
+ .toLowerCase()
143
+ .replace(/[\s-]+/g, '_');
144
+ var aliases = {
145
+ no_op: 'no_op_submit',
146
+ no_op_submit: 'no_op_submit',
147
+ submit_noop: 'no_op_submit',
148
+ missing_data: 'missing_wrong_data',
149
+ wrong_data: 'missing_wrong_data',
150
+ missing_wrong_data: 'missing_wrong_data',
151
+ filter_mismatch: 'filter_query_mismatch',
152
+ query_mismatch: 'filter_query_mismatch',
153
+ filter_query_mismatch: 'filter_query_mismatch',
154
+ invoice_pdf_export: 'invoice_pdf_export',
155
+ pdf_export: 'invoice_pdf_export',
156
+ export: 'invoice_pdf_export',
157
+ upload: 'upload_import',
158
+ import: 'upload_import',
159
+ upload_import: 'upload_import',
160
+ route_auth: 'route_auth_hydration',
161
+ auth_hydration: 'route_auth_hydration',
162
+ route_auth_hydration: 'route_auth_hydration',
163
+ slow_query: 'slow_query_performance',
164
+ performance: 'slow_query_performance',
165
+ slow_query_performance: 'slow_query_performance'
166
+ };
167
+ return aliases[normalized] || '';
168
+ }
169
+ function normalizeReproductionStatus(value) {
170
+ var normalized = cleanText(value, 80).toLowerCase();
171
+ if (/blocked|unable|cannot/.test(normalized)) {
172
+ return 'blocked';
173
+ }
174
+ if (/classif|triag|inferred/.test(normalized)) {
175
+ return 'classified';
176
+ }
177
+ return 'reproduced';
178
+ }
179
+ function normalizeSupportDiagnosisEvidence(values) {
180
+ var allowed = new Set(['ticket', 'browser', 'mongo', 'log', 'code', 'commit', 'qa', 'other']);
181
+ if (!Array.isArray(values)) {
182
+ var summary = cleanText(values, 1200);
183
+ return summary ? [{ type: 'other', summary: summary }] : [];
184
+ }
185
+ var stringEvidence = values
186
+ .filter(function (entry) { return typeof entry === 'string'; })
187
+ .map(function (entry) { return ({
188
+ type: 'other',
189
+ summary: cleanText(entry, 1200)
190
+ }); });
191
+ var objectEvidence = values
192
+ .filter(function (entry) { return entry && typeof entry === 'object' && !Array.isArray(entry); })
193
+ .map(function (entry) {
194
+ var type = cleanText(entry.type, 80).toLowerCase();
195
+ return {
196
+ type: (allowed.has(type) ? type : 'other'),
197
+ summary: cleanText(entry.summary || entry.message || entry.evidence || entry.reason, 1200),
198
+ artifactPath: cleanText(entry.artifactPath || entry.path || entry.file, 500)
199
+ };
200
+ });
201
+ return stringEvidence.concat(objectEvidence)
202
+ .filter(function (entry) { return entry.summary; })
203
+ .slice(0, 20);
204
+ }
205
+ function normalizeSupportDiagnosisHints(values) {
206
+ return (Array.isArray(values) ? values : [])
207
+ .map(function (entry) {
208
+ if (typeof entry === 'string') {
209
+ return { reason: cleanText(entry, 500) };
210
+ }
211
+ var value = cleanObject(entry);
212
+ return {
213
+ id: cleanText(value.id || value._id, 160),
214
+ ticketNumber: cleanText(value.ticketNumber || value.ticket_number || value.sourceTicketNumber, 80),
215
+ title: cleanText(value.title || value.summary, 300),
216
+ outcome: cleanText(value.outcome || value.status, 80),
217
+ issueClass: cleanText(value.issueClass || value.issue_class, 80),
218
+ ownerFiles: cleanList(value.ownerFiles || value.owner_files || value.files, 8, 240),
219
+ commitSha: cleanText(value.commitSha || value.commit_sha, 80),
220
+ commitMessage: cleanText(value.commitMessage || value.commit_message, 300),
221
+ reason: cleanText(value.reason || value.matchReason || value.match_reason, 500)
222
+ };
223
+ })
224
+ .filter(function (entry) { return entry.id || entry.ticketNumber || entry.title || entry.reason || entry.commitSha; })
225
+ .slice(0, 8);
226
+ }
227
+ function normalizeOwnerFilePath(value) {
228
+ return cleanText(value, 500)
229
+ .replace(/\\/g, '/')
230
+ .replace(/^\.\/+/, '')
231
+ .replace(/^\/+/, '')
232
+ .replace(/\s+$/g, '');
233
+ }
234
+ function ownerFileLooksBroad(value) {
235
+ var normalized = normalizeOwnerFilePath(value);
236
+ return !normalized
237
+ || normalized.includes('*')
238
+ || normalized.endsWith('/')
239
+ || !/\.[a-z0-9]+$/i.test(normalized)
240
+ || /^(\.|src|server|angular|client|app|lib|packages?)$/i.test(normalized)
241
+ || /(^|\/)(node_modules|dist|build|coverage|\.git)(\/|$)/i.test(normalized);
242
+ }
243
+ function normalizeResolveIOSupportDiagnosisGate(value, now) {
244
+ var source = cleanObject(value);
245
+ if (!Object.keys(source).length) {
246
+ return undefined;
247
+ }
248
+ var issueCaseSource = cleanObject(source.issue_case || source.issueCase);
249
+ var hypothesisSource = cleanObject(source.accepted_hypothesis || source.acceptedHypothesis);
250
+ var failingPathSource = cleanObject(source.failing_path || source.failingPath);
251
+ var proofPlanSource = cleanObject(source.proof_plan || source.proofPlan);
252
+ var issueClass = normalizeIssueClass(source.issue_class || source.issueClass);
253
+ var ownerFiles = cleanList(source.owner_files || source.ownerFiles, 20, 500)
254
+ .map(normalizeOwnerFilePath)
255
+ .filter(Boolean);
256
+ var gate = {
257
+ issue_case: {
258
+ customer_complaint: pickText(issueCaseSource, ['customer_complaint', 'customerComplaint', 'complaint', 'request', 'summary'], 1200),
259
+ expected_result: pickText(issueCaseSource, ['expected_result', 'expectedResult', 'expected'], 1000),
260
+ observed_result: pickText(issueCaseSource, ['observed_result', 'observedResult', 'observed', 'actual'], 1000),
261
+ route_module: pickText(issueCaseSource, ['route_module', 'routeModule', 'route', 'module', 'screen'], 500),
262
+ account_customer_context: pickText(issueCaseSource, ['account_customer_context', 'accountCustomerContext', 'account', 'customer', 'user', 'context'], 800),
263
+ reproduction_status: normalizeReproductionStatus(issueCaseSource.reproduction_status || issueCaseSource.reproductionStatus || source.reproduction_status),
264
+ reproduction_blocker: pickText(issueCaseSource, ['reproduction_blocker', 'reproductionBlocker', 'blocked_reason', 'blockedReason'], 1000)
265
+ },
266
+ issue_class: issueClass || 'missing_wrong_data',
267
+ accepted_hypothesis: {
268
+ statement: pickText(hypothesisSource, ['statement', 'hypothesis', 'root_cause', 'rootCause', 'summary'], 1200)
269
+ || (typeof source.accepted_hypothesis === 'string' ? cleanText(source.accepted_hypothesis, 1200) : ''),
270
+ falsifiable_test: pickText(hypothesisSource, ['falsifiable_test', 'falsifiableTest', 'test', 'proof', 'falsifier'], 1000),
271
+ evidence: cleanList(hypothesisSource.evidence || source.hypothesis_evidence || source.hypothesisEvidence, 10, 800)
272
+ },
273
+ rejected_alternatives: cleanList(source.rejected_alternatives || source.rejectedAlternatives, 10, 700),
274
+ failing_path: {
275
+ frontend: pickText(failingPathSource, ['frontend', 'frontend_path', 'frontendPath', 'eventPath'], 700),
276
+ backend: pickText(failingPathSource, ['backend', 'backend_path', 'backendPath', 'methodPublicationPath'], 700),
277
+ shared_library: pickText(failingPathSource, ['shared_library', 'sharedLibrary', 'library', 'lib'], 700),
278
+ data_query: pickText(failingPathSource, ['data_query', 'dataQuery', 'query'], 700),
279
+ description: pickText(failingPathSource, ['description', 'path', 'summary'], 1200) || cleanText(source.failing_path, 1200)
280
+ },
281
+ owner_files: ownerFiles,
282
+ proof_plan: {
283
+ before: pickText(proofPlanSource, ['before', 'before_state', 'beforeState', 'precondition'], 1000),
284
+ before_state_unavailable_reason: pickText(proofPlanSource, ['before_state_unavailable_reason', 'beforeStateUnavailableReason', 'before_unavailable_reason'], 1000),
285
+ action: pickText(proofPlanSource, ['action', 'browser_action', 'browserAction', 'steps'], 1000),
286
+ after: pickText(proofPlanSource, ['after', 'after_state', 'afterState', 'expected_after'], 1000),
287
+ business_assertion: pickText(proofPlanSource, ['business_assertion', 'businessAssertion', 'assertion'], 1000),
288
+ route: pickText(proofPlanSource, ['route', 'url'], 500),
289
+ data_assertion: pickText(proofPlanSource, ['data_assertion', 'dataAssertion', 'mongo_delta', 'mongoDelta'], 1000),
290
+ artifact_expectation: pickText(proofPlanSource, ['artifact_expectation', 'artifactExpectation', 'artifact', 'screenshot'], 1000)
291
+ },
292
+ similar_tickets: normalizeSupportDiagnosisHints(source.similar_tickets || source.similarTickets),
293
+ similar_commits: normalizeSupportDiagnosisHints(source.similar_commits || source.similarCommits),
294
+ evidence: normalizeSupportDiagnosisEvidence(source.evidence),
295
+ status: cleanText(source.status, 80).toLowerCase() || 'incomplete',
296
+ updatedAt: isoNow(now || source.updatedAt || source.updated_at)
297
+ };
298
+ if (!['missing', 'incomplete', 'blocked', 'passed'].includes(gate.status)) {
299
+ gate.status = 'incomplete';
300
+ }
301
+ return gate;
302
+ }
303
+ function extractResolveIOSupportDiagnosisGateFromText(value, now) {
304
+ var e_3, _a;
305
+ var text = String(value || '').trim();
306
+ if (!text) {
307
+ return undefined;
308
+ }
309
+ var candidates = [];
310
+ var fenced = Array.from(text.matchAll(/```(?:json)?\s*([\s\S]*?)```/gi)).map(function (match) { return match[1]; });
311
+ candidates.push.apply(candidates, __spreadArray([], __read(fenced), false));
312
+ var jsonBlock = text.match(/\{[\s\S]*\}/);
313
+ if (jsonBlock) {
314
+ candidates.push(jsonBlock[0]);
315
+ }
316
+ try {
317
+ for (var candidates_1 = __values(candidates), candidates_1_1 = candidates_1.next(); !candidates_1_1.done; candidates_1_1 = candidates_1.next()) {
318
+ var candidate = candidates_1_1.value;
319
+ try {
320
+ var parsed = JSON.parse(candidate);
321
+ var wrapped = (parsed === null || parsed === void 0 ? void 0 : parsed.support_diagnosis_gate) || (parsed === null || parsed === void 0 ? void 0 : parsed.supportDiagnosisGate) || (parsed === null || parsed === void 0 ? void 0 : parsed.diagnosis_gate) || (parsed === null || parsed === void 0 ? void 0 : parsed.diagnosisGate) || parsed;
322
+ var normalized = normalizeResolveIOSupportDiagnosisGate(wrapped, now);
323
+ if (normalized) {
324
+ return normalized;
325
+ }
326
+ }
327
+ catch (_b) {
328
+ // Continue trying less exact JSON candidates.
329
+ }
330
+ }
331
+ }
332
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
333
+ finally {
334
+ try {
335
+ if (candidates_1_1 && !candidates_1_1.done && (_a = candidates_1.return)) _a.call(candidates_1);
336
+ }
337
+ finally { if (e_3) throw e_3.error; }
338
+ }
339
+ return undefined;
340
+ }
341
+ function validateResolveIOSupportDiagnosisGate(value, options) {
342
+ if (options === void 0) { options = {}; }
343
+ var normalized = normalizeResolveIOSupportDiagnosisGate(value);
344
+ if (!normalized) {
345
+ return { valid: false, status: 'missing', blockers: ['SupportDiagnosisGate is missing.'] };
346
+ }
347
+ var blockers = [];
348
+ var maxOwnerFiles = Math.max(1, Number(options.maxOwnerFiles || 8) || 8);
349
+ if (!normalized.issue_case.customer_complaint) {
350
+ blockers.push('Diagnosis issue_case.customer_complaint is required.');
351
+ }
352
+ if (!normalized.issue_case.expected_result) {
353
+ blockers.push('Diagnosis issue_case.expected_result is required.');
354
+ }
355
+ if (!normalized.issue_case.observed_result) {
356
+ blockers.push('Diagnosis issue_case.observed_result is required.');
357
+ }
358
+ if (!normalized.issue_case.route_module) {
359
+ blockers.push('Diagnosis issue_case.route_module is required.');
360
+ }
361
+ if (!normalized.issue_case.account_customer_context) {
362
+ blockers.push('Diagnosis issue_case.account_customer_context is required.');
363
+ }
364
+ if (normalized.issue_case.reproduction_status === 'blocked' && !normalized.issue_case.reproduction_blocker) {
365
+ blockers.push('Diagnosis blocked reproduction requires issue_case.reproduction_blocker.');
366
+ }
367
+ if (!normalizeIssueClass(normalized.issue_class)) {
368
+ blockers.push('Diagnosis issue_class must be one of the supported issue-class probes.');
369
+ }
370
+ if (!normalized.accepted_hypothesis.statement) {
371
+ blockers.push('Diagnosis accepted_hypothesis.statement is required.');
372
+ }
373
+ if (!normalized.accepted_hypothesis.falsifiable_test) {
374
+ blockers.push('Diagnosis accepted_hypothesis.falsifiable_test is required.');
375
+ }
376
+ if (!normalized.accepted_hypothesis.evidence.length) {
377
+ blockers.push('Diagnosis accepted_hypothesis.evidence must cite proof.');
378
+ }
379
+ if (!normalized.rejected_alternatives.length) {
380
+ blockers.push('Diagnosis rejected_alternatives must include at least one rejected theory.');
381
+ }
382
+ if (!normalized.failing_path.description
383
+ && !normalized.failing_path.frontend
384
+ && !normalized.failing_path.backend
385
+ && !normalized.failing_path.shared_library
386
+ && !normalized.failing_path.data_query) {
387
+ blockers.push('Diagnosis failing_path must identify frontend, backend, query, shared library, or path description.');
388
+ }
389
+ if (!normalized.owner_files.length) {
390
+ blockers.push('Diagnosis owner_files must contain the small editable file set.');
391
+ }
392
+ if (normalized.owner_files.length > maxOwnerFiles) {
393
+ blockers.push("Diagnosis owner_files has ".concat(normalized.owner_files.length, " entries; maximum is ").concat(maxOwnerFiles, "."));
394
+ }
395
+ var broadFiles = normalized.owner_files.filter(ownerFileLooksBroad);
396
+ if (broadFiles.length) {
397
+ blockers.push("Diagnosis owner_files contains broad or unsafe path(s): ".concat(broadFiles.join(', '), "."));
398
+ }
399
+ if (!normalized.proof_plan.before && !normalized.proof_plan.before_state_unavailable_reason) {
400
+ blockers.push('Diagnosis proof_plan.before is required unless proof_plan.before_state_unavailable_reason explains why before-state proof is impossible.');
401
+ }
402
+ if (!normalized.proof_plan.action) {
403
+ blockers.push('Diagnosis proof_plan.action is required.');
404
+ }
405
+ if (!normalized.proof_plan.after) {
406
+ blockers.push('Diagnosis proof_plan.after is required.');
407
+ }
408
+ if (!normalized.proof_plan.business_assertion) {
409
+ blockers.push('Diagnosis proof_plan.business_assertion is required.');
410
+ }
411
+ if (!normalized.evidence.length) {
412
+ blockers.push('Diagnosis evidence must include ticket/code/browser/log/Mongo proof.');
413
+ }
414
+ normalized.status = blockers.length ? 'incomplete' : 'passed';
415
+ return {
416
+ valid: blockers.length === 0,
417
+ status: normalized.status,
418
+ blockers: blockers,
419
+ normalized: normalized
420
+ };
421
+ }
422
+ function buildResolveIOSupportIssueClassProbes(value) {
423
+ var validation = validateResolveIOSupportDiagnosisGate(value);
424
+ var gate = validation.normalized || normalizeResolveIOSupportDiagnosisGate(value);
425
+ if (!gate) {
426
+ return [];
427
+ }
428
+ var route = gate.proof_plan.route || gate.issue_case.route_module;
429
+ var proof = gate.proof_plan.business_assertion;
430
+ var common = {
431
+ issue_class: gate.issue_class,
432
+ probe_type: 'issue_class_probe',
433
+ route: route,
434
+ blocks_acceptance_without_business_assertion: true
435
+ };
436
+ var map = {
437
+ no_op_submit: {
438
+ action: "Submit the customer action on ".concat(route || 'the affected screen', " and assert a persisted state change or explicit validation message."),
439
+ expected: proof || 'Before/action/after proof shows the submit is no longer a no-op.'
440
+ },
441
+ missing_wrong_data: {
442
+ action: "Load the named record/list on ".concat(route || 'the affected route', " and compare visible data to the expected persisted source."),
443
+ expected: proof || 'Visible data and persisted data match the customer expectation.'
444
+ },
445
+ filter_query_mismatch: {
446
+ action: 'Apply the reported filter/query inputs and assert the returned rows/counts match the expected dataset.',
447
+ expected: proof || 'Filter/query output contains the correct included rows and excludes the wrong rows.'
448
+ },
449
+ invoice_pdf_export: {
450
+ action: 'Generate the invoice/PDF/export from the affected route and inspect the downloaded/generated artifact.',
451
+ expected: proof || 'Generated artifact contains the expected customer-visible rows, totals, or fields.'
452
+ },
453
+ upload_import: {
454
+ action: 'Run the upload/import workflow with a representative file and assert parsed plus persisted results.',
455
+ expected: proof || 'Import shows a success result and persisted rows/counts changed as expected.'
456
+ },
457
+ route_auth_hydration: {
458
+ action: 'Open the route as the affected user and assert authenticated hydration reaches the functional screen, not a shell.',
459
+ expected: proof || 'Route hydrates with the required controls/data for the affected account.'
460
+ },
461
+ slow_query_performance: {
462
+ action: 'Run the reported query/workflow with timing/log evidence before and after the fix.',
463
+ expected: proof || 'Performance evidence shows the slow path improved without changing results.'
464
+ }
465
+ };
466
+ var selected = map[gate.issue_class];
467
+ return [__assign(__assign({}, common), { objective: "Issue-class probe for ".concat(gate.issue_class, ": ").concat(gate.issue_case.customer_complaint), action: selected.action, expected_evidence: selected.expected })];
468
+ }
469
+ function hashResolveIOSupportV5Evidence(value) {
470
+ var raw = typeof value === 'string' ? value : JSON.stringify(value || {});
471
+ var normalized = cleanText(raw, 8000)
472
+ .toLowerCase()
473
+ .replace(/[a-f0-9]{16,}/g, '<id>')
474
+ .replace(/\b\d{2,}\b/g, '<n>');
475
+ var hash = 0;
476
+ for (var index = 0; index < normalized.length; index += 1) {
477
+ hash = ((hash << 5) - hash + normalized.charCodeAt(index)) | 0;
478
+ }
479
+ return "ev-".concat(Math.abs(hash).toString(36) || '0');
480
+ }
481
+ function decideResolveIOSupportV5RepeatedFailureStop(input) {
482
+ var failureClass = cleanText(input.failureClass || 'unknown', 80).toLowerCase();
483
+ var blockerFingerprint = fingerprintResolveIOSupportV5Blocker(input.blocker || '');
484
+ var evidenceHash = cleanText(input.evidenceHash, 80) || hashResolveIOSupportV5Evidence(input.evidence || input.blocker || '');
485
+ var limit = Math.max(1, Number(input.limit || 2) || 2);
486
+ var latestRecord = (input.history || [])[(input.history || []).length - 1];
487
+ var managerDecision = (0, ai_runner_manager_policy_1.decideResolveIOAIManagerPolicy)({
488
+ history: (input.history || []).map(function (entry) { return ({
489
+ outcome: entry.outcome,
490
+ lane: entry.lane,
491
+ stepType: entry.stepType,
492
+ failureClass: entry.failureClass,
493
+ blocker: entry.blocker || entry.summary,
494
+ blockerFingerprint: entry.blockerFingerprint,
495
+ evidenceHash: entry.evidenceHash,
496
+ changedFiles: entry.changedFiles,
497
+ artifactPaths: entry.artifactPaths,
498
+ summary: entry.summary,
499
+ recordedAt: entry.recordedAt
500
+ }); }),
501
+ current: {
502
+ outcome: 'needs_repair',
503
+ lane: latestRecord === null || latestRecord === void 0 ? void 0 : latestRecord.lane,
504
+ stepType: latestRecord === null || latestRecord === void 0 ? void 0 : latestRecord.stepType,
505
+ failureClass: failureClass,
506
+ blocker: input.blocker,
507
+ blockerFingerprint: blockerFingerprint,
508
+ evidenceHash: evidenceHash
509
+ },
510
+ maxSameFailureRepeats: limit,
511
+ maxPingPongTransitions: 3,
512
+ infraFailureClasses: input.ignoreInfra !== false ? ['infra', 'compile'] : []
513
+ });
514
+ if (managerDecision.action === 'retry_infra') {
515
+ return {
516
+ shouldStop: false,
517
+ repeatedCount: 0,
518
+ failureClass: failureClass,
519
+ blockerFingerprint: blockerFingerprint,
520
+ evidenceHash: evidenceHash,
521
+ reason: 'support_v5_infra_failures_do_not_count_as_product_repair_loops'
522
+ };
523
+ }
524
+ if (managerDecision.action === 'park_ping_pong') {
525
+ return {
526
+ shouldStop: true,
527
+ repeatedCount: managerDecision.pingPongCount,
528
+ failureClass: failureClass,
529
+ blockerFingerprint: blockerFingerprint,
530
+ evidenceHash: evidenceHash,
531
+ reason: 'support_v5_ping_pong_failure_loop'
532
+ };
533
+ }
534
+ if (managerDecision.action === 'park_repeated_failure') {
535
+ return {
536
+ shouldStop: true,
537
+ repeatedCount: managerDecision.sameFailureCount,
538
+ failureClass: failureClass,
539
+ blockerFingerprint: blockerFingerprint,
540
+ evidenceHash: evidenceHash,
541
+ reason: 'support_v5_same_failure_class_without_new_evidence'
542
+ };
543
+ }
544
+ var repeatedCount = 0;
545
+ for (var index = (input.history || []).length - 1; index >= 0; index -= 1) {
546
+ var item = input.history[index];
547
+ if (item.outcome === 'pass' || item.outcome === 'ready_for_merge') {
548
+ break;
549
+ }
550
+ var itemFailureClass = cleanText(item.failureClass || 'unknown', 80).toLowerCase();
551
+ var itemBlockerFingerprint = cleanText(item.blockerFingerprint, 80)
552
+ || fingerprintResolveIOSupportV5Blocker(item.blocker || item.summary || '');
553
+ var itemEvidenceHash = cleanText(item.evidenceHash, 80)
554
+ || hashResolveIOSupportV5Evidence(item.artifactPaths || item.blocker || item.summary || '');
555
+ if (itemFailureClass !== failureClass || itemBlockerFingerprint !== blockerFingerprint || itemEvidenceHash !== evidenceHash) {
556
+ break;
557
+ }
558
+ repeatedCount += 1;
559
+ }
560
+ return {
561
+ shouldStop: repeatedCount >= limit,
562
+ repeatedCount: repeatedCount,
563
+ failureClass: failureClass,
564
+ blockerFingerprint: blockerFingerprint,
565
+ evidenceHash: evidenceHash,
566
+ reason: repeatedCount >= limit
567
+ ? 'support_v5_same_failure_class_without_new_evidence'
568
+ : 'support_v5_retry_allowed_new_or_below_repeat_limit'
569
+ };
570
+ }
571
+ function changedFilesOutsideResolveIOSupportDiagnosisOwnerFiles(diagnosisGate, changedFiles, options) {
572
+ if (options === void 0) { options = {}; }
573
+ var validation = validateResolveIOSupportDiagnosisGate(diagnosisGate);
574
+ if (!validation.valid || !validation.normalized) {
575
+ return cleanList(changedFiles, 80, 500);
576
+ }
577
+ var owners = new Set(validation.normalized.owner_files.map(normalizeOwnerFilePath));
578
+ return cleanList(changedFiles, 120, 500)
579
+ .map(normalizeOwnerFilePath)
580
+ .filter(function (filePath) {
581
+ if (!filePath) {
582
+ return false;
583
+ }
584
+ if (owners.has(filePath)) {
585
+ return false;
586
+ }
587
+ if (options.allowTests && /(^|\/)(tests?|spec|__tests__)(\/|$)|\.(?:spec|test)\.[jt]sx?$/i.test(filePath)) {
588
+ return false;
589
+ }
590
+ return true;
591
+ });
592
+ }
593
+ function applyResolveIOSupportDiagnosisGateToMicrotasks(bundle, diagnosisGate) {
594
+ var validation = validateResolveIOSupportDiagnosisGate(diagnosisGate);
595
+ var gate = validation.normalized;
596
+ if (!gate) {
597
+ return bundle;
598
+ }
599
+ var ownerFiles = gate.owner_files;
600
+ var probes = buildResolveIOSupportIssueClassProbes(gate);
601
+ var now = isoNow();
602
+ var ledger = (bundle.supportV5MicrotaskLedger || []).map(function (task) {
603
+ var _a;
604
+ if (task.type === 'diagnosis_gate') {
605
+ return __assign(__assign({}, task), { status: validation.valid ? 'pass' : 'needs_repair', blocker: validation.valid ? '' : validation.blockers.join(' | '), updatedAt: now });
606
+ }
607
+ if (task.lane === 'build' && /repair|product_repair|build_repair/i.test(String(task.type || ''))) {
608
+ return __assign(__assign({}, task), { targetFiles: ownerFiles, contextRefs: Array.from(new Set(__spreadArray(__spreadArray([], __read((task.contextRefs || [])), false), ['supportV5DiagnosisGate', 'owner_files'], false))), selfGate: "Repair only the diagnosed owner files unless you revise the diagnosis with new evidence. Owner files: ".concat(ownerFiles.join(', '), "."), acceptanceProof: gate.proof_plan.business_assertion, dependsOn: Array.from(new Set(__spreadArray(__spreadArray([], __read((task.dependsOn || [])), false), [stableIdFromText('diagnosis', bundle.supportV5ScopeDigest || gate.issue_case.customer_complaint)], false))), updatedAt: now });
609
+ }
610
+ if (task.lane === 'qa' && task.type === 'qa_row') {
611
+ return __assign(__assign({}, task), { contextRefs: Array.from(new Set(__spreadArray(__spreadArray([], __read((task.contextRefs || [])), false), ['supportV5DiagnosisGate', 'proof_plan'], false))), selfGate: ((_a = probes[0]) === null || _a === void 0 ? void 0 : _a.action) || task.selfGate, acceptanceProof: gate.proof_plan.business_assertion || task.acceptanceProof, targetFiles: ownerFiles, updatedAt: now });
612
+ }
613
+ return task;
614
+ });
615
+ var nextActive = selectResolveIOSupportV5ActiveMicrotask(ledger, bundle.supportV5ActiveMicrotaskId);
616
+ return __assign(__assign({}, bundle), { supportV5DiagnosisGate: gate, supportV5MicrotaskLedger: ledger, supportV5ActiveMicrotaskId: nextActive === null || nextActive === void 0 ? void 0 : nextActive.microtaskId, supportV5LaneMemory: __assign(__assign({}, bundle.supportV5LaneMemory), { build: __assign(__assign({}, bundle.supportV5LaneMemory.build), { changedFiles: ownerFiles, scopeSummary: [
617
+ bundle.supportV5LaneMemory.build.scopeSummary,
618
+ "Diagnosis issue class: ".concat(gate.issue_class),
619
+ "Accepted hypothesis: ".concat(gate.accepted_hypothesis.statement),
620
+ "Owner files: ".concat(ownerFiles.join(', '))
621
+ ].filter(Boolean).join(' | '), updatedAt: now }), qa: __assign(__assign({}, bundle.supportV5LaneMemory.qa), { activeQaRow: {
622
+ workflow: gate.proof_plan.business_assertion,
623
+ route: gate.proof_plan.route || gate.issue_case.route_module,
624
+ assertion: gate.proof_plan.after,
625
+ status: 'pending'
626
+ }, updatedAt: now }) }) });
627
+ }
107
628
  function stableIdFromText(prefix, value) {
108
629
  var text = cleanText(value, 2000).toLowerCase();
109
630
  var hash = 0;
@@ -166,7 +687,7 @@ function buildResolveIOSupportV5ScopeDigest(input) {
166
687
  return raw.slice(0, maxChars);
167
688
  }
168
689
  function buildResolveIOSupportV5MicrotaskLedger(input) {
169
- var e_2, _a;
690
+ var e_4, _a;
170
691
  var existing = Array.isArray(input.existing) ? input.existing : [];
171
692
  var completedByObjective = new Map();
172
693
  try {
@@ -177,12 +698,12 @@ function buildResolveIOSupportV5MicrotaskLedger(input) {
177
698
  }
178
699
  }
179
700
  }
180
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
701
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
181
702
  finally {
182
703
  try {
183
704
  if (existing_1_1 && !existing_1_1.done && (_a = existing_1.return)) _a.call(existing_1);
184
705
  }
185
- finally { if (e_2) throw e_2.error; }
706
+ finally { if (e_4) throw e_4.error; }
186
707
  }
187
708
  var now = isoNow(input.now);
188
709
  var requirements = cleanList(input.requirements, 30, 240);
@@ -190,6 +711,28 @@ function buildResolveIOSupportV5MicrotaskLedger(input) {
190
711
  ? requirements
191
712
  : cleanText(input.scopeDigest, 1000).split(/\s+\|\s+|\r?\n/g).map(function (line) { return line.trim(); }).filter(Boolean).slice(0, 12);
192
713
  var ledger = [];
714
+ var diagnosisObjective = "Root-cause-first diagnosis gate for: ".concat(cleanText(input.scopeDigest, 360) || 'support ticket');
715
+ var diagnosisId = stableIdFromText('diagnosis', diagnosisObjective);
716
+ var existingDiagnosis = existing.find(function (task) { return (task === null || task === void 0 ? void 0 : task.type) === 'diagnosis_gate' || (task === null || task === void 0 ? void 0 : task.microtaskId) === diagnosisId; });
717
+ ledger.push(existingDiagnosis && (existingDiagnosis.status === 'pass' || existingDiagnosis.status === 'parked') ? existingDiagnosis : {
718
+ microtaskId: diagnosisId,
719
+ lane: 'build',
720
+ type: 'diagnosis_gate',
721
+ status: (existingDiagnosis === null || existingDiagnosis === void 0 ? void 0 : existingDiagnosis.status) || 'pending',
722
+ objective: diagnosisObjective,
723
+ targetFiles: [],
724
+ contextRefs: ['scope_digest', 'support_context', 'similar_tickets', 'similar_commits'],
725
+ selfGate: 'Read-only diagnosis only: reproduce or explicitly classify the issue, accept one falsifiable root-cause hypothesis, reject alternatives, identify the failing path, cap owner_files, and define before/action/after business proof.',
726
+ acceptanceProof: 'Valid ResolveIOSupportDiagnosisGate JSON with issue_case, issue_class, accepted_hypothesis, rejected_alternatives, failing_path, owner_files, proof_plan, evidence, and status=passed.',
727
+ threadKey: input.buildThreadKey,
728
+ promptTokenEstimate: existingDiagnosis === null || existingDiagnosis === void 0 ? void 0 : existingDiagnosis.promptTokenEstimate,
729
+ attempts: (existingDiagnosis === null || existingDiagnosis === void 0 ? void 0 : existingDiagnosis.attempts) || 0,
730
+ dependsOn: [],
731
+ parentScopeId: stableIdFromText('scope', diagnosisObjective),
732
+ blocker: existingDiagnosis === null || existingDiagnosis === void 0 ? void 0 : existingDiagnosis.blocker,
733
+ createdAt: (existingDiagnosis === null || existingDiagnosis === void 0 ? void 0 : existingDiagnosis.createdAt) || now,
734
+ updatedAt: (existingDiagnosis === null || existingDiagnosis === void 0 ? void 0 : existingDiagnosis.updatedAt) || now
735
+ });
193
736
  sourceRequirements.forEach(function (requirement, index) {
194
737
  var objective = cleanText(requirement, 240);
195
738
  if (!objective) {
@@ -210,7 +753,7 @@ function buildResolveIOSupportV5MicrotaskLedger(input) {
210
753
  acceptanceProof: 'Concrete code/data proof for this behavior, with changed files listed.',
211
754
  threadKey: input.buildThreadKey,
212
755
  attempts: 0,
213
- dependsOn: [],
756
+ dependsOn: [diagnosisId],
214
757
  parentScopeId: stableIdFromText('scope', objective),
215
758
  createdAt: now,
216
759
  updatedAt: now
@@ -227,7 +770,7 @@ function buildResolveIOSupportV5MicrotaskLedger(input) {
227
770
  acceptanceProof: 'QA matrix row pass with route/data assertion, screenshot/caption artifact, and persisted before/after row/count/value proof for data-changing workflows.',
228
771
  threadKey: input.qaThreadKey,
229
772
  attempts: 0,
230
- dependsOn: [buildId],
773
+ dependsOn: [diagnosisId, buildId],
231
774
  parentScopeId: stableIdFromText('scope', objective),
232
775
  createdAt: now,
233
776
  updatedAt: now
@@ -248,7 +791,7 @@ function selectResolveIOSupportV5ActiveMicrotask(ledger, preferredId) {
248
791
  || ledger.find(function (task) { return task.status === 'blocked'; });
249
792
  }
250
793
  function initializeResolveIOSupportV5State(input) {
251
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
794
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
252
795
  var now = isoNow(input.now);
253
796
  var existing = input.existing || {};
254
797
  var existingSupervisor = existing.supportV5SupervisorState;
@@ -260,6 +803,8 @@ function initializeResolveIOSupportV5State(input) {
260
803
  var buildThreadKey = cleanText(input.buildThreadKey || ((_a = existingLaneMemory.build) === null || _a === void 0 ? void 0 : _a.threadKey) || "support:".concat(input.ticketId || input.jobId, ":job:").concat(input.jobId, ":build"), 240);
261
804
  var qaThreadKey = cleanText(input.qaThreadKey || ((_b = existingLaneMemory.qa) === null || _b === void 0 ? void 0 : _b.threadKey) || "support:".concat(input.ticketId || input.jobId, ":job:").concat(input.jobId, ":qa"), 240);
262
805
  var budget = buildResolveIOSupportV5Budget(existing.supportV5Budget);
806
+ var existingDiagnosisGate = normalizeResolveIOSupportDiagnosisGate(existing.supportV5DiagnosisGate);
807
+ var diagnosisValidation = validateResolveIOSupportDiagnosisGate(existingDiagnosisGate);
263
808
  var scopeDigest = cleanText(existing.supportV5ScopeDigest, 4000) || buildResolveIOSupportV5ScopeDigest({
264
809
  goal: (existingSupervisor === null || existingSupervisor === void 0 ? void 0 : existingSupervisor.currentGoal) || "Resolve support ticket ".concat(ticketLabel),
265
810
  approvedScope: scope,
@@ -274,7 +819,7 @@ function initializeResolveIOSupportV5State(input) {
274
819
  existing: existing.supportV5MicrotaskLedger
275
820
  });
276
821
  var activeMicrotask = selectResolveIOSupportV5ActiveMicrotask(ledger, existing.supportV5ActiveMicrotaskId);
277
- return {
822
+ var initialized = {
278
823
  supportWorkflowVersion: 'v5',
279
824
  supportV5SupervisorState: {
280
825
  version: 'v5',
@@ -282,8 +827,8 @@ function initializeResolveIOSupportV5State(input) {
282
827
  currentGoal: (existingSupervisor === null || existingSupervisor === void 0 ? void 0 : existingSupervisor.currentGoal) || "Resolve support ticket ".concat(ticketLabel),
283
828
  approvedScope: (existingSupervisor === null || existingSupervisor === void 0 ? void 0 : existingSupervisor.approvedScope) || scope,
284
829
  prBranch: cleanText(input.prBranch || (existingSupervisor === null || existingSupervisor === void 0 ? void 0 : existingSupervisor.prBranch) || '', 240),
285
- activeStep: (existingSupervisor === null || existingSupervisor === void 0 ? void 0 : existingSupervisor.activeStep) || 'compile_check',
286
- activeBlocker: (existingSupervisor === null || existingSupervisor === void 0 ? void 0 : existingSupervisor.activeBlocker) || '',
830
+ activeStep: (existingSupervisor === null || existingSupervisor === void 0 ? void 0 : existingSupervisor.activeStep) || (diagnosisValidation.valid ? 'compile_check' : 'diagnosis_gate'),
831
+ activeBlocker: (existingSupervisor === null || existingSupervisor === void 0 ? void 0 : existingSupervisor.activeBlocker) || (diagnosisValidation.valid ? '' : 'SupportDiagnosisGate required before product-code repair.'),
287
832
  lastGoodCheckpoint: (existingSupervisor === null || existingSupervisor === void 0 ? void 0 : existingSupervisor.lastGoodCheckpoint) || 'v5_initialized',
288
833
  currentQaRow: existingSupervisor === null || existingSupervisor === void 0 ? void 0 : existingSupervisor.currentQaRow,
289
834
  processLease: input.processLease || (existingSupervisor === null || existingSupervisor === void 0 ? void 0 : existingSupervisor.processLease),
@@ -291,6 +836,7 @@ function initializeResolveIOSupportV5State(input) {
291
836
  noEmailUnlessApproved: true,
292
837
  updatedAt: now
293
838
  },
839
+ supportV5DiagnosisGate: diagnosisValidation.valid ? diagnosisValidation.normalized : existingDiagnosisGate,
294
840
  supportV5LaneMemory: {
295
841
  build: {
296
842
  lane: 'build',
@@ -325,24 +871,49 @@ function initializeResolveIOSupportV5State(input) {
325
871
  ? existing.supportV5RunnerIncidents.slice(-80)
326
872
  : [],
327
873
  supportV5MicrotaskLedger: ledger,
328
- supportV5ActiveMicrotaskId: activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.microtaskId,
874
+ supportV5ActiveMicrotaskId: diagnosisValidation.valid
875
+ ? activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.microtaskId
876
+ : ((_u = ledger.find(function (task) { return task.type === 'diagnosis_gate' && !['pass', 'parked'].includes(task.status); })) === null || _u === void 0 ? void 0 : _u.microtaskId) || (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.microtaskId),
329
877
  supportV5ScopeDigest: scopeDigest,
330
878
  supportV5MicrotaskUsageHistory: Array.isArray(existing.supportV5MicrotaskUsageHistory)
331
879
  ? existing.supportV5MicrotaskUsageHistory.slice(-200)
880
+ : [],
881
+ supportV5FailureFingerprints: Array.isArray(existing.supportV5FailureFingerprints)
882
+ ? existing.supportV5FailureFingerprints.slice(-200)
332
883
  : []
333
884
  };
885
+ return diagnosisValidation.valid && diagnosisValidation.normalized
886
+ ? applyResolveIOSupportDiagnosisGateToMicrotasks(initialized, diagnosisValidation.normalized)
887
+ : initialized;
334
888
  }
335
889
  function recordResolveIOSupportV5Step(bundle, step) {
336
- var _a, _b;
890
+ var _a, _b, _c, _d;
337
891
  var now = isoNow(step.now);
338
892
  var promptTokens = Math.max(0, Number(step.promptTokenEstimate || 0) || 0);
339
893
  var runtimeMs = Math.max(0, Number(step.runtimeMs || 0) || 0);
340
894
  var microtaskId = cleanText(step.microtaskId || bundle.supportV5ActiveMicrotaskId, 160);
341
- var record = __assign(__assign({}, (microtaskId ? { microtaskId: microtaskId } : {})), { stepType: step.stepType, outcome: step.outcome, lane: step.lane, model: cleanText(step.model, 80), threadKey: cleanText(step.threadKey, 240), promptTokenEstimate: promptTokens || undefined, runtimeMs: runtimeMs || undefined, summary: cleanText(step.summary || step.blocker || step.outcome, 1200), blocker: cleanText(step.blocker, 1200), changedFiles: cleanList(step.changedFiles, 80, 500), artifactPaths: cleanList(step.artifactPaths, 80, 500), recordedAt: now });
895
+ var normalizedDiagnosisGate = step.diagnosisGate
896
+ ? normalizeResolveIOSupportDiagnosisGate(step.diagnosisGate, now)
897
+ : undefined;
898
+ var blockerFingerprint = step.blocker || step.summary
899
+ ? fingerprintResolveIOSupportV5Blocker(step.blocker || step.summary || '')
900
+ : undefined;
901
+ var evidenceHash = cleanText(step.evidenceHash, 80)
902
+ || (((_a = step.artifactPaths) === null || _a === void 0 ? void 0 : _a.length) || step.blocker || step.summary
903
+ ? hashResolveIOSupportV5Evidence(((_b = step.artifactPaths) === null || _b === void 0 ? void 0 : _b.length) ? step.artifactPaths : "".concat(step.blocker || '', "\n").concat(step.summary || ''))
904
+ : (0, ai_runner_manager_policy_1.hashResolveIOAIManagerEvidence)({
905
+ failureClass: step.failureClass,
906
+ blocker: step.blocker,
907
+ summary: step.summary,
908
+ changedFiles: step.changedFiles,
909
+ artifactPaths: step.artifactPaths
910
+ }));
911
+ var record = __assign(__assign({}, (microtaskId ? { microtaskId: microtaskId } : {})), { stepType: step.stepType, outcome: step.outcome, lane: step.lane, model: cleanText(step.model, 80), threadKey: cleanText(step.threadKey, 240), promptTokenEstimate: promptTokens || undefined, runtimeMs: runtimeMs || undefined, summary: cleanText(step.summary || step.blocker || step.outcome, 1200), blocker: cleanText(step.blocker, 1200), changedFiles: cleanList(step.changedFiles, 80, 500), artifactPaths: cleanList(step.artifactPaths, 80, 500), diagnosisGate: normalizedDiagnosisGate, failureClass: cleanText(step.failureClass, 80) || undefined, blockerFingerprint: blockerFingerprint, evidenceHash: evidenceHash, recordedAt: now });
912
+ var diagnosisGate = normalizedDiagnosisGate || bundle.supportV5DiagnosisGate;
342
913
  var laneMemory = __assign({}, bundle.supportV5LaneMemory);
343
914
  if (step.lane === 'build' || step.lane === 'qa') {
344
915
  var previous = laneMemory[step.lane];
345
- laneMemory[step.lane] = __assign(__assign({}, previous), { activeBlocker: record.blocker || previous.activeBlocker || '', activeQaRow: step.activeQaRow || previous.activeQaRow, changedFiles: ((_a = record.changedFiles) === null || _a === void 0 ? void 0 : _a.length) ? record.changedFiles : previous.changedFiles, artifactPaths: ((_b = record.artifactPaths) === null || _b === void 0 ? void 0 : _b.length) ? record.artifactPaths : previous.artifactPaths, latestPromptTokenEstimate: promptTokens || previous.latestPromptTokenEstimate, updatedAt: now });
916
+ laneMemory[step.lane] = __assign(__assign({}, previous), { activeBlocker: record.blocker || previous.activeBlocker || '', activeQaRow: step.activeQaRow || previous.activeQaRow, changedFiles: ((_c = record.changedFiles) === null || _c === void 0 ? void 0 : _c.length) ? record.changedFiles : previous.changedFiles, artifactPaths: ((_d = record.artifactPaths) === null || _d === void 0 ? void 0 : _d.length) ? record.artifactPaths : previous.artifactPaths, latestPromptTokenEstimate: promptTokens || previous.latestPromptTokenEstimate, updatedAt: now });
346
917
  }
347
918
  var supervisor = __assign(__assign({}, bundle.supportV5SupervisorState), { status: step.outcome === 'ready_for_merge' ? 'complete' : (step.outcome === 'park_manual' || step.outcome === 'budget_stop' ? 'parked' : 'active'), activeStep: step.stepType, activeBlocker: record.blocker || '', currentQaRow: step.activeQaRow || bundle.supportV5SupervisorState.currentQaRow, lastGoodCheckpoint: step.outcome === 'pass' || step.outcome === 'ready_for_merge'
348
919
  ? step.stepType
@@ -360,8 +931,37 @@ function recordResolveIOSupportV5Step(bundle, step) {
360
931
  : 'in_progress';
361
932
  return __assign(__assign({}, task), { status: status, blocker: record.blocker || task.blocker, promptTokenEstimate: promptTokens || task.promptTokenEstimate, attempts: task.attempts + (step.outcome === 'pass' || step.outcome === 'ready_for_merge' ? 0 : 1), updatedAt: now });
362
933
  });
934
+ var failureFingerprint = record.failureClass && record.blockerFingerprint && record.evidenceHash
935
+ ? {
936
+ stepType: record.stepType,
937
+ failureClass: cleanText(record.failureClass, 80),
938
+ blockerFingerprint: record.blockerFingerprint,
939
+ evidenceHash: record.evidenceHash,
940
+ recordedAt: now
941
+ }
942
+ : undefined;
943
+ var managerDecision = (0, ai_runner_manager_policy_1.decideResolveIOAIManagerPolicy)({
944
+ history: __spreadArray(__spreadArray([], __read(bundle.supportV5StepHistory), false), [record], false),
945
+ current: record,
946
+ maxSameFailureRepeats: buildResolveIOSupportV5Budget(bundle.supportV5Budget).maxRepeatedNoProgress,
947
+ maxPingPongTransitions: 3,
948
+ infraFailureClasses: ['infra', 'compile']
949
+ });
950
+ var previousRecord = bundle.supportV5StepHistory[bundle.supportV5StepHistory.length - 1];
951
+ var nextLoopCount = managerDecision.loopBudgetShouldReset
952
+ || (previousRecord === null || previousRecord === void 0 ? void 0 : previousRecord.failureClass) !== record.failureClass
953
+ || (previousRecord === null || previousRecord === void 0 ? void 0 : previousRecord.blockerFingerprint) !== record.blockerFingerprint
954
+ || (previousRecord === null || previousRecord === void 0 ? void 0 : previousRecord.evidenceHash) !== record.evidenceHash
955
+ ? 1
956
+ : bundle.supportV5Budget.loopCount + 1;
363
957
  var nextMicrotask = selectResolveIOSupportV5ActiveMicrotask(ledger, bundle.supportV5ActiveMicrotaskId);
364
- return __assign(__assign({}, bundle), { supportV5SupervisorState: supervisor, supportV5LaneMemory: laneMemory, supportV5StepHistory: __spreadArray(__spreadArray([], __read(bundle.supportV5StepHistory), false), [record], false).slice(-100), supportV5Budget: __assign(__assign({}, bundle.supportV5Budget), { totalPromptTokenEstimate: bundle.supportV5Budget.totalPromptTokenEstimate + promptTokens, totalRuntimeMs: bundle.supportV5Budget.totalRuntimeMs + runtimeMs, loopCount: bundle.supportV5Budget.loopCount + 1 }), supportV5MicrotaskLedger: ledger, supportV5ActiveMicrotaskId: nextMicrotask === null || nextMicrotask === void 0 ? void 0 : nextMicrotask.microtaskId, supportV5MicrotaskUsageHistory: bundle.supportV5MicrotaskUsageHistory || [] });
958
+ var nextBundle = __assign(__assign({}, bundle), { supportV5SupervisorState: supervisor, supportV5DiagnosisGate: diagnosisGate, supportV5LaneMemory: laneMemory, supportV5StepHistory: __spreadArray(__spreadArray([], __read(bundle.supportV5StepHistory), false), [record], false).slice(-100), supportV5Budget: __assign(__assign({}, bundle.supportV5Budget), { totalPromptTokenEstimate: bundle.supportV5Budget.totalPromptTokenEstimate + promptTokens, totalRuntimeMs: bundle.supportV5Budget.totalRuntimeMs + runtimeMs, loopCount: nextLoopCount }), supportV5MicrotaskLedger: ledger, supportV5ActiveMicrotaskId: nextMicrotask === null || nextMicrotask === void 0 ? void 0 : nextMicrotask.microtaskId, supportV5MicrotaskUsageHistory: bundle.supportV5MicrotaskUsageHistory || [], supportV5FailureFingerprints: failureFingerprint
959
+ ? __spreadArray(__spreadArray([], __read((bundle.supportV5FailureFingerprints || [])), false), [failureFingerprint], false).slice(-200)
960
+ : (bundle.supportV5FailureFingerprints || []) });
961
+ if (normalizedDiagnosisGate && validateResolveIOSupportDiagnosisGate(normalizedDiagnosisGate).valid) {
962
+ return applyResolveIOSupportDiagnosisGateToMicrotasks(nextBundle, normalizedDiagnosisGate);
963
+ }
964
+ return nextBundle;
365
965
  }
366
966
  function recordResolveIOSupportV5MicrotaskUsage(bundle, usage) {
367
967
  var record = __assign(__assign({}, usage), { microtaskId: cleanText(usage.microtaskId, 160), threadKey: cleanText(usage.threadKey, 240), model: cleanText(usage.model, 80), promptTokenEstimate: Math.max(0, Number(usage.promptTokenEstimate || 0) || 0), promptSections: Array.isArray(usage.promptSections)
@@ -400,6 +1000,14 @@ function decideResolveIOSupportV5Continuation(bundle) {
400
1000
  }
401
1001
  var budgetExceeded = budget.loopCount >= budget.maxLoopsPerTicket
402
1002
  || ((last === null || last === void 0 ? void 0 : last.promptTokenEstimate) || 0) > budget.maxPromptTokensPerNonInitialStep;
1003
+ var repeatedFailure = last ? decideResolveIOSupportV5RepeatedFailureStop({
1004
+ history: history,
1005
+ failureClass: last.failureClass,
1006
+ blocker: last.blocker || last.summary,
1007
+ evidenceHash: last.evidenceHash,
1008
+ limit: budget.maxRepeatedNoProgress,
1009
+ ignoreInfra: true
1010
+ }) : null;
403
1011
  if (budgetExceeded) {
404
1012
  return {
405
1013
  action: 'park',
@@ -418,6 +1026,15 @@ function decideResolveIOSupportV5Continuation(bundle) {
418
1026
  budgetExceeded: budgetExceeded
419
1027
  };
420
1028
  }
1029
+ if (repeatedFailure === null || repeatedFailure === void 0 ? void 0 : repeatedFailure.shouldStop) {
1030
+ return {
1031
+ action: 'park',
1032
+ reason: repeatedFailure.reason,
1033
+ nextStep: (last === null || last === void 0 ? void 0 : last.stepType) || 'cleanup',
1034
+ repeatedNoProgressCount: repeatedFailure.repeatedCount,
1035
+ budgetExceeded: budgetExceeded
1036
+ };
1037
+ }
421
1038
  return {
422
1039
  action: 'continue',
423
1040
  reason: 'support_v5_continue',
@@ -451,6 +1068,9 @@ function buildResolveIOSupportV5DiagnoseFirstPrompt(lines) {
451
1068
  function buildResolveIOSupportV5MicrotaskPrompt(input) {
452
1069
  var _a, _b, _c;
453
1070
  var activeMicrotask = selectResolveIOSupportV5ActiveMicrotask(input.bundle.supportV5MicrotaskLedger || [], input.bundle.supportV5ActiveMicrotaskId);
1071
+ var diagnosisValidation = validateResolveIOSupportDiagnosisGate(input.bundle.supportV5DiagnosisGate);
1072
+ var diagnosisGate = diagnosisValidation.normalized || input.bundle.supportV5DiagnosisGate;
1073
+ var diagnosisActive = (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.type) === 'diagnosis_gate';
454
1074
  var budget = buildResolveIOSupportV5PromptBudget();
455
1075
  var repairLike = Boolean(input.failureText || (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.status) === 'needs_repair' || /repair/i.test(String(input.stage || (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.type) || '')));
456
1076
  var cap = repairLike
@@ -469,7 +1089,9 @@ function buildResolveIOSupportV5MicrotaskPrompt(input) {
469
1089
  var artifactPaths = cleanList(((_b = input.artifactPaths) === null || _b === void 0 ? void 0 : _b.length) ? input.artifactPaths : laneMemory.artifactPaths, 8, 200);
470
1090
  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);
471
1091
  var contextSnippets = cleanList(input.contextSnippets, 5, 360);
472
- var qaRow = input.activeQaRow || (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.lane) === 'qa' ? input.activeQaRow || laneMemory.activeQaRow || input.bundle.supportV5SupervisorState.currentQaRow : undefined;
1092
+ var qaRow = input.activeQaRow || (activeMicrotask === null || activeMicrotask === void 0 ? void 0 : activeMicrotask.lane) === 'qa'
1093
+ ? input.activeQaRow || laneMemory.activeQaRow || input.bundle.supportV5SupervisorState.currentQaRow
1094
+ : undefined;
473
1095
  var sections = [
474
1096
  {
475
1097
  name: 'microtask_contract',
@@ -479,11 +1101,33 @@ function buildResolveIOSupportV5MicrotaskPrompt(input) {
479
1101
  'Do exactly one microtask and one proof gate. Do not replay ticket triage, prior plans, attachments, broad QA checklist, or unrelated scope.',
480
1102
  'If context is insufficient, request the smallest missing file/log/artifact by path and park this microtask; do not broaden the prompt.',
481
1103
  'Do not send customer email. Do not deploy. Do not spawn duplicate server/client/Mongo/browser/Codex processes.',
482
- input.lane === 'qa'
483
- ? 'QA lane hard boundary: the platform preflight owns compile, dependency install, Mongo/server/client startup, and Angular startup. This lane owns only browser/data proof and QA artifacts unless the prompt explicitly says preflight was skipped.'
484
- : 'Build lane hard boundary: do not run `npm run build-dev`, `ng build`, `npm run server`, `npm run client`, `ng serve`, `run-local-qa.sh`, browser automation, or any watch/long-lived command. If a broad compile gate is needed, run only `npm run build-prod -- --watch=false`; otherwise use a targeted finite check or return the precise blocker.'
1104
+ diagnosisActive
1105
+ ? 'Diagnosis gate hard boundary: read-only investigation only. Do not edit source, generated files, package files, tests, fixtures, QA artifacts, or local data. Return the diagnosis JSON contract only.'
1106
+ : input.lane === 'qa'
1107
+ ? 'QA lane hard boundary: the platform preflight owns compile, dependency install, Mongo/server/client startup, and Angular startup. This lane owns only browser/data proof and QA artifacts unless the prompt explicitly says preflight was skipped.'
1108
+ : 'Build lane hard boundary: do not run `npm run build-dev`, `ng build`, `npm run server`, `npm run client`, `ng serve`, `run-local-qa.sh`, browser automation, or any watch/long-lived command. If a broad compile gate is needed, run only `npm run build-prod -- --watch=false`; otherwise use a targeted finite check or return the precise blocker.'
485
1109
  ].join('\n')
486
1110
  },
1111
+ diagnosisActive ? {
1112
+ name: 'root_cause_first_diagnosis_contract',
1113
+ text: [
1114
+ 'Before any product-code repair, produce strict JSON only:',
1115
+ '{"support_diagnosis_gate":{"issue_case":{"customer_complaint":"","expected_result":"","observed_result":"","route_module":"","account_customer_context":"","reproduction_status":"reproduced|blocked|classified","reproduction_blocker":""},"issue_class":"no_op_submit|missing_wrong_data|filter_query_mismatch|invoice_pdf_export|upload_import|route_auth_hydration|slow_query_performance","accepted_hypothesis":{"statement":"","falsifiable_test":"","evidence":[""]},"rejected_alternatives":[""],"failing_path":{"frontend":"","backend":"","shared_library":"","data_query":"","description":""},"owner_files":["small/exact/file.ts"],"proof_plan":{"before":"","before_state_unavailable_reason":"","action":"","after":"","business_assertion":"","route":"","data_assertion":"","artifact_expectation":""},"similar_tickets":[],"similar_commits":[],"evidence":[{"type":"ticket|browser|mongo|log|code|commit|qa|other","summary":"","artifactPath":""}],"status":"passed"}}',
1116
+ 'Owner files must be a small exact editable set, not directories, globs, generated wrappers, or broad repo areas.',
1117
+ 'The accepted hypothesis must be falsifiable and backed by evidence; prior similar tickets or commits are hints only and cannot bypass fresh diagnosis.',
1118
+ 'The proof plan must be before/action/after business proof. If before-state proof is impossible, explain exactly why in before_state_unavailable_reason.'
1119
+ ].join('\n')
1120
+ } : {
1121
+ name: 'diagnosis_gate_context',
1122
+ text: diagnosisValidation.valid && diagnosisGate ? [
1123
+ "Diagnosis issue class: ".concat(diagnosisGate.issue_class),
1124
+ "Accepted hypothesis: ".concat(diagnosisGate.accepted_hypothesis.statement),
1125
+ "Failing path: ".concat(diagnosisGate.failing_path.description || diagnosisGate.failing_path.frontend || diagnosisGate.failing_path.backend || ''),
1126
+ "Owner files: ".concat(diagnosisGate.owner_files.join(', ')),
1127
+ "Business proof required: ".concat(diagnosisGate.proof_plan.business_assertion),
1128
+ "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)
1129
+ ].filter(Boolean).join('\n') : 'SupportDiagnosisGate is not valid. Park instead of editing product code.'
1130
+ },
487
1131
  {
488
1132
  name: 'scope_digest',
489
1133
  text: cleanText(input.bundle.supportV5ScopeDigest || input.bundle.supportV5SupervisorState.approvedScope, 900)
@@ -542,9 +1186,11 @@ function buildResolveIOSupportV5MicrotaskPrompt(input) {
542
1186
  },
543
1187
  {
544
1188
  name: 'return_contract',
545
- text: input.lane === 'qa'
546
- ? 'Return strict JSON only: {"status":"pass"|"needs-fix"|"blocked","microtaskId":"","summary":"","evidence":[""],"artifacts":[""],"next_actions":[""]}.'
547
- : 'Return concise Markdown with: Microtask Result, Root Cause, Changes, Self-Gate, Acceptance Proof, Residual Risk.'
1189
+ text: diagnosisActive
1190
+ ? 'Return strict JSON only with support_diagnosis_gate. Do not include Markdown and do not edit files.'
1191
+ : input.lane === 'qa'
1192
+ ? 'Return strict JSON only: {"status":"pass"|"needs-fix"|"blocked","microtaskId":"","summary":"","evidence":[""],"artifacts":[""],"next_actions":[""]}.'
1193
+ : 'Return concise Markdown with: Microtask Result, Root Cause, Changes, Self-Gate, Acceptance Proof, Residual Risk.'
548
1194
  }
549
1195
  ].filter(function (section) { return cleanText(section.text, 20); });
550
1196
  var promptSections = sections.map(function (section) { return ({
@@ -570,7 +1216,7 @@ function buildResolveIOSupportV5MicrotaskPrompt(input) {
570
1216
  };
571
1217
  }
572
1218
  function summarizeResolveIOSupportV5MicrotaskUsage(bundle) {
573
- var e_3, _a, e_4, _b;
1219
+ var e_5, _a, e_6, _b;
574
1220
  var byMicrotask = new Map();
575
1221
  var bySection = new Map();
576
1222
  var totalPromptTokenEstimate = 0;
@@ -585,17 +1231,17 @@ function summarizeResolveIOSupportV5MicrotaskUsage(bundle) {
585
1231
  existing.calls += 1;
586
1232
  byMicrotask.set(usage.microtaskId, existing);
587
1233
  try {
588
- for (var _e = (e_4 = void 0, __values(usage.promptSections || [])), _f = _e.next(); !_f.done; _f = _e.next()) {
1234
+ for (var _e = (e_6 = void 0, __values(usage.promptSections || [])), _f = _e.next(); !_f.done; _f = _e.next()) {
589
1235
  var section = _f.value;
590
1236
  bySection.set(section.name, (bySection.get(section.name) || 0) + section.tokenEstimate);
591
1237
  }
592
1238
  }
593
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
1239
+ catch (e_6_1) { e_6 = { error: e_6_1 }; }
594
1240
  finally {
595
1241
  try {
596
1242
  if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
597
1243
  }
598
- finally { if (e_4) throw e_4.error; }
1244
+ finally { if (e_6) throw e_6.error; }
599
1245
  }
600
1246
  var hardCap = usage.lane === 'qa' ? promptBudget.qaMicrotaskHardCap : promptBudget.buildMicrotaskHardCap;
601
1247
  if ((usage.promptTokenEstimate || 0) > hardCap) {
@@ -603,12 +1249,12 @@ function summarizeResolveIOSupportV5MicrotaskUsage(bundle) {
603
1249
  }
604
1250
  }
605
1251
  }
606
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
1252
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
607
1253
  finally {
608
1254
  try {
609
1255
  if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
610
1256
  }
611
- finally { if (e_3) throw e_3.error; }
1257
+ finally { if (e_5) throw e_5.error; }
612
1258
  }
613
1259
  return {
614
1260
  totalPromptTokenEstimate: totalPromptTokenEstimate,