@vypdev/copilot 3.9.2 → 3.10.0

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.
@@ -68,6 +68,45 @@ function runAtApplicationErrorBoundary(operation) {
68
68
  }
69
69
 
70
70
 
71
+ /***/ }),
72
+
73
+ /***/ 2937:
74
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
75
+
76
+
77
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
78
+ exports.BugbotMutationError = void 0;
79
+ exports.bugbotMutationError = bugbotMutationError;
80
+ const application_error_1 = __nccwpck_require__(5999);
81
+ const pull_request_review_errors_1 = __nccwpck_require__(6445);
82
+ class BugbotMutationError extends application_error_1.ApplicationError {
83
+ constructor(diagnostic) {
84
+ super(diagnostic.errorCode, `Bugbot ${diagnostic.stage} failed: operation=${diagnostic.operation}; finding=${diagnostic.findingId}; affected=${diagnostic.affectedCount}; ${diagnostic.providerStatus}; provider-reference=${diagnostic.providerReference}. Completed effects are retained; correct the named cause and recheck the same target.`);
85
+ this.diagnostic = diagnostic;
86
+ }
87
+ }
88
+ exports.BugbotMutationError = BugbotMutationError;
89
+ function bugbotMutationError(cause, stage, findingIds, fallback, affectedCount = findingIds.length) {
90
+ if (cause instanceof BugbotMutationError)
91
+ return cause;
92
+ const provider = cause instanceof pull_request_review_errors_1.PullRequestReviewOperationError ? cause : undefined;
93
+ const status = provider?.providerStatus;
94
+ const errorCode = status === 401 ? 'authorization.credential-invalid' : status === 403 ? 'authorization.denied'
95
+ : status === 404 ? 'provider.not-found' : status === 409 ? 'provider.conflict'
96
+ : status === 429 ? 'provider.rate-limited'
97
+ : status === 408 || status === 425 ? 'provider.unavailable'
98
+ : status && status < 500 ? 'provider.contract-invalid' : 'provider.unavailable';
99
+ const first = findingIds[0];
100
+ return new BugbotMutationError(Object.freeze({
101
+ stage, operation: provider?.operation ?? fallback,
102
+ findingId: typeof first === 'string' && /^[A-Za-z0-9_./:-]{1,200}$/.test(first) ? first : 'unavailable',
103
+ affectedCount: Math.min(affectedCount, 10000),
104
+ providerStatus: status ? `http-${status}` : 'http-unavailable',
105
+ providerReference: provider?.providerReference ?? 'unavailable', errorCode,
106
+ }));
107
+ }
108
+
109
+
71
110
  /***/ }),
72
111
 
73
112
  /***/ 601:
@@ -796,6 +835,7 @@ exports.BUGBOT_MESSAGE_IDS = Object.freeze([
796
835
  'bugbot.overflow.body',
797
836
  'bugbot.common.more',
798
837
  'bugbot.diagnostic.operationFailed',
838
+ 'bugbot.diagnostic.findingMutationFailed',
799
839
  'bugbot.diagnostic.identityUnavailable',
800
840
  'bugbot.diagnostic.pullRequestCommentsFailed',
801
841
  'bugbot.diagnostic.reviewThreadsFailed',
@@ -881,6 +921,7 @@ const ENGLISH_MESSAGES = Object.freeze({
881
921
  'bugbot.overflow.heading': 'More findings (comment limit)',
882
922
  'bugbot.overflow.body': Object.freeze({ one: 'There is {count} more finding that was not published as an individual comment. Review locally or in the full diff to see the list.', other: 'There are {count} more findings that were not published as individual comments. Review locally or in the full diff to see the list.' }),
883
923
  'bugbot.common.more': Object.freeze({ one: 'and {count} more.', other: 'and {count} more.' }),
924
+ 'bugbot.diagnostic.findingMutationFailed': 'Finding mutation failed: stage={stage}; operation={operation}; finding={findingId}; affected={affectedCount}; {providerStatus}; provider reference={providerReference}. Completed effects are retained. Correct access/contract errors before retrying; for transient failures restore provider availability, then recheck the same PR. Recheck reconciles existing reviews and threads.',
884
925
  'bugbot.diagnostic.operationFailed': 'Bugbot could not complete one or more finding mutations.',
885
926
  'bugbot.diagnostic.identityUnavailable': 'The authenticated Bugbot identity is unavailable.',
886
927
  'bugbot.diagnostic.pullRequestCommentsFailed': 'Unable to re-read pull request review comments.',
@@ -970,6 +1011,7 @@ const SPANISH_MESSAGES = Object.freeze({
970
1011
  'bugbot.overflow.heading': 'Más hallazgos (límite de comentarios)',
971
1012
  'bugbot.overflow.body': Object.freeze({ one: 'Hay {count} hallazgo más que no se publicó como comentario individual. Revísalo localmente o en el diff completo para consultar la lista.', many: 'Hay {count} hallazgos más que no se publicaron como comentarios individuales. Revísalos localmente o en el diff completo para consultar la lista.', other: 'Hay {count} hallazgos más que no se publicaron como comentarios individuales. Revísalos localmente o en el diff completo para consultar la lista.' }),
972
1013
  'bugbot.common.more': Object.freeze({ one: 'y {count} más.', many: 'y {count} más.', other: 'y {count} más.' }),
1014
+ 'bugbot.diagnostic.findingMutationFailed': 'Falló una mutación: fase={stage}; operación={operation}; hallazgo={findingId}; afectados={affectedCount}; {providerStatus}; referencia del proveedor={providerReference}. Se conservan los efectos completados. Corrige acceso/contrato antes de reintentar; para fallos transitorios restaura el proveedor y revisa la misma PR. La revisión reconcilia comentarios e hilos existentes.',
973
1015
  'bugbot.diagnostic.operationFailed': 'Bugbot no pudo completar una o más mutaciones de hallazgos.',
974
1016
  'bugbot.diagnostic.identityUnavailable': 'La identidad autenticada de Bugbot no está disponible.',
975
1017
  'bugbot.diagnostic.pullRequestCommentsFailed': 'No se pudieron volver a leer los comentarios del review del pull request.',
@@ -1009,6 +1051,7 @@ async function resolveBugbotCatalog(locale, configuration, resolver) {
1009
1051
  }
1010
1052
  function renderBugbotDiagnostic(diagnostic, catalog) {
1011
1053
  switch (diagnostic.code) {
1054
+ case 'finding-mutation-failed': return catalog.message('bugbot.diagnostic.findingMutationFailed', { ...diagnostic.mutation });
1012
1055
  case 'operation-failed': return catalog.message('bugbot.diagnostic.operationFailed');
1013
1056
  case 'identity-unavailable': return catalog.message('bugbot.diagnostic.identityUnavailable');
1014
1057
  case 'snapshot-pull-request-comments-failed': return catalog.message('bugbot.diagnostic.pullRequestCommentsFailed');
@@ -1558,6 +1601,10 @@ function renderBugbotStatusCard(projection, catalogOrLocale, links) {
1558
1601
  facts.push(catalog.message('bugbot.coverage.omitted', { count: source.omittedItems }));
1559
1602
  if (source.truncatedItems > 0)
1560
1603
  facts.push(catalog.message('bugbot.coverage.truncated', { count: source.truncatedItems }));
1604
+ const truncatedIds = source.truncatedItemIds?.slice(0, 50)
1605
+ .filter(id => /^(?:issue:[0-9]+|review:[A-Za-z0-9_=-]+)$/.test(id) && id.length <= 160);
1606
+ if (truncatedIds?.length)
1607
+ facts.push(`truncated-source-ids=${truncatedIds.join(', ')}`);
1561
1608
  if (source.providerLimitReached)
1562
1609
  facts.push(catalog.message('bugbot.coverage.providerLimit'));
1563
1610
  return `- ${source.source}: ${source.status}; ${facts.join(', ')}`;
@@ -1647,9 +1694,21 @@ function normalizeHistoricalSnapshot(originalBody, analyzedHeadSha, catalog) {
1647
1694
  function renderFindingRow(finding) {
1648
1695
  const label = (0, github_comment_publication_policy_1.sanitizeAgentMarkdown)(finding.title || finding.id, 500).replace(/[\r\n]+/gu, ' ');
1649
1696
  const state = stateLabel(finding.state);
1697
+ const identity = finding.state === 'unknown'
1698
+ ? ` — ${renderFindingId(finding.id)}`
1699
+ : '';
1650
1700
  return finding.url
1651
- ? `- ${state} — [${label}](${finding.url})`
1652
- : `- ${state} — ${label}`;
1701
+ ? `- ${state} — [${label}](${finding.url})${identity}`
1702
+ : `- ${state} — ${label}${identity}`;
1703
+ }
1704
+ function renderFindingId(value) {
1705
+ const id = (0, github_comment_publication_policy_1.sanitizeAgentMarkdown)(value, 200).replace(/[\r\n]+/gu, ' ');
1706
+ // A delimiter longer than every embedded backtick run keeps links, images
1707
+ // and HTML inert even when the marker permits arbitrary Markdown punctuation.
1708
+ let delimiter = '`';
1709
+ while (id.includes(delimiter))
1710
+ delimiter += '`';
1711
+ return `${delimiter} ${id} ${delimiter}`;
1653
1712
  }
1654
1713
  function stateLabel(state) {
1655
1714
  return `[ ] ${state}`;
@@ -2136,6 +2195,13 @@ class PullRequestReviewOperationError extends Error {
2136
2195
  super(buildMessage(operation, context));
2137
2196
  this.name = "PullRequestReviewOperationError";
2138
2197
  this.operation = operation;
2198
+ const status = context?.providerStatus;
2199
+ if (typeof status === 'number' && Number.isInteger(status) && status >= 400 && status <= 599) {
2200
+ this.providerStatus = status;
2201
+ }
2202
+ if (typeof context?.providerReference === 'string' && /^[A-Za-z0-9:-]{1,64}$/.test(context.providerReference)) {
2203
+ this.providerReference = context.providerReference;
2204
+ }
2139
2205
  }
2140
2206
  }
2141
2207
  exports.PullRequestReviewOperationError = PullRequestReviewOperationError;
@@ -2235,7 +2301,7 @@ function partitionFailureCategory(error) {
2235
2301
  return error instanceof Error ? error.name : 'unknown';
2236
2302
  }
2237
2303
  function suppressDismissedFindings(execution, context, prepared) {
2238
- const activeFindings = (prepared.activeFindings ?? prepared.toPublish).filter((finding) => {
2304
+ const activeFindings = (0, finding_1.retainExistingFindingIds)(prepared.activeFindings ?? prepared.toPublish, context.existingByFindingId).filter((finding) => {
2239
2305
  const existing = (0, finding_1.findExistingFindingInfo)(context.existingByFindingId, finding);
2240
2306
  return existing?.issue?.resolution !== 'dismissed' && existing?.pullRequest?.resolution !== 'dismissed';
2241
2307
  });
@@ -2254,6 +2320,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
2254
2320
  exports.applyDetectedFindings = applyDetectedFindings;
2255
2321
  const mark_findings_resolved_use_case_1 = __nccwpck_require__(6963);
2256
2322
  const publish_findings_use_case_1 = __nccwpck_require__(8442);
2323
+ const bugbot_mutation_error_1 = __nccwpck_require__(2937);
2257
2324
  const pull_request_review_errors_1 = __nccwpck_require__(6445);
2258
2325
  async function applyDetectedFindings(operation, context, prepared, publicationPorts, resolutionPorts, catalog) {
2259
2326
  try {
@@ -2269,7 +2336,7 @@ async function applyDetectedFindings(operation, context, prepared, publicationPo
2269
2336
  });
2270
2337
  }
2271
2338
  catch (error) {
2272
- const publicationError = error instanceof pull_request_review_errors_1.PullRequestReviewOperationError
2339
+ const publicationError = error instanceof bugbot_mutation_error_1.BugbotMutationError || error instanceof pull_request_review_errors_1.PullRequestReviewOperationError
2273
2340
  ? error
2274
2341
  : new Error("Unable to publish findings.");
2275
2342
  return [publicationError];
@@ -2540,6 +2607,7 @@ function buildPreviousFindingsContext(previousFindings) {
2540
2607
  `;
2541
2608
  const suffix = `
2542
2609
  **Your task 2:** For each finding above, analyze the current code and decide:
2610
+ - Trace the original failure precondition through current callers, validation helpers and effective configuration, including modules outside the original anchor. A retained finding is not proof that its old explanation is still true. Reuse its exact id if reporting the same defect again; do not create a second report for it.
2543
2611
  - If the problem **still exists** (same code or same issue present): do **not** include it in \`resolved_findings\`.
2544
2612
  - If the problem **no longer applies** (e.g. that code was removed or refactored away): include \`{ "id": "<exact id>", "resolution": "obsolete" }\` in \`resolved_findings\`.
2545
2613
  - If the problem **has been fixed** (code was changed and the issue is resolved): include \`{ "id": "<exact id>", "resolution": "fixed" }\` in \`resolved_findings\`.
@@ -2658,6 +2726,10 @@ function buildReviewConversationContext(issueComments, commentsByPullRequest, bo
2658
2726
  omitted,
2659
2727
  truncated: chronological.filter((entry) => entry.truncated).length,
2660
2728
  retained: chronological.length,
2729
+ ...(chronological.some(entry => entry.truncated) ? {
2730
+ truncatedItemIds: chronological.filter(entry => entry.truncated)
2731
+ .map(entry => entry.providerId).filter(id => /^(?:issue:[0-9]+|review:[A-Za-z0-9_=-]+)$/.test(id) && id.length <= 160),
2732
+ } : {}),
2661
2733
  };
2662
2734
  }
2663
2735
  function appendConversationEntry(entries, author, kind, body, createdAt, providerId) {
@@ -3339,6 +3411,7 @@ async function loadBugbotContext(request, ports, resolvedPreflight) {
3339
3411
  itemsFetched: conversationContext.retained + conversationContext.omitted,
3340
3412
  omittedItems: conversationContext.omitted,
3341
3413
  truncatedItems: conversationContext.truncated,
3414
+ ...(conversationContext.truncatedItemIds ? { truncatedItemIds: conversationContext.truncatedItemIds } : {}),
3342
3415
  limitReached: conversationContext.omitted > 0 || conversationContext.truncated > 0,
3343
3416
  },
3344
3417
  {
@@ -3537,11 +3610,11 @@ Object.defineProperty(exports, "markFindingsResolved", ({ enumerable: true, get:
3537
3610
 
3538
3611
  Object.defineProperty(exports, "__esModule", ({ value: true }));
3539
3612
  exports.markFindingsResolved = markFindingsResolved;
3540
- const pull_request_review_errors_1 = __nccwpck_require__(6445);
3541
3613
  const logging_ports_1 = __nccwpck_require__(6152);
3542
3614
  const resolve_issue_finding_1 = __nccwpck_require__(5300);
3543
3615
  const resolve_pull_request_finding_1 = __nccwpck_require__(4567);
3544
3616
  const review_state_1 = __nccwpck_require__(9200);
3617
+ const bugbot_mutation_error_1 = __nccwpck_require__(2937);
3545
3618
  const application_error_1 = __nccwpck_require__(5999);
3546
3619
  async function markFindingsResolved(param) {
3547
3620
  const errors = [];
@@ -3569,8 +3642,8 @@ async function repairExistingPullRequestFinding(ports, operation, findingId, des
3569
3642
  try {
3570
3643
  await ports.pullRequestComments.unresolvePullRequestReviewThread(destination.pullRequestNumber, destination.commentIdentity);
3571
3644
  }
3572
- catch {
3573
- addResolutionError(errors, 'pull request');
3645
+ catch (cause) {
3646
+ addResolutionError(errors, 'pull request', findingId, cause);
3574
3647
  }
3575
3648
  }
3576
3649
  }
@@ -3584,7 +3657,7 @@ async function resolveIssueIfNeeded(param, findingId, destination, errors) {
3584
3657
  return;
3585
3658
  const comment = param.context.issueComments.find(item => item.id === destination.commentId);
3586
3659
  if (comment?.body == null) {
3587
- addResolutionError(errors, 'issue');
3660
+ addResolutionError(errors, 'issue', findingId);
3588
3661
  return;
3589
3662
  }
3590
3663
  try {
@@ -3595,8 +3668,8 @@ async function resolveIssueIfNeeded(param, findingId, destination, errors) {
3595
3668
  resolution: param.resolvedFindingResolutions?.get(findingId),
3596
3669
  }, param.catalog);
3597
3670
  }
3598
- catch {
3599
- addResolutionError(errors, 'issue');
3671
+ catch (cause) {
3672
+ addResolutionError(errors, 'issue', findingId, cause);
3600
3673
  }
3601
3674
  }
3602
3675
  async function tryResolvePullRequestFinding(ports, findingId, destination, errors, resolution, catalog) {
@@ -3608,17 +3681,14 @@ async function tryResolvePullRequestFinding(ports, findingId, destination, error
3608
3681
  resolution,
3609
3682
  }, catalog);
3610
3683
  }
3611
- catch {
3612
- addResolutionError(errors, 'pull request');
3684
+ catch (cause) {
3685
+ addResolutionError(errors, 'pull request', findingId, cause);
3613
3686
  }
3614
3687
  }
3615
- function addResolutionError(errors, destination) {
3616
- const cause = destination === 'pull request'
3617
- ? new pull_request_review_errors_1.PullRequestReviewOperationError('mark-resolved')
3618
- : new Error('Unable to mark an issue finding as resolved.');
3619
- const semanticError = new application_error_1.ApplicationError('provider.unavailable', destination === 'pull request'
3620
- ? 'Unable to mark a pull request finding as resolved.'
3621
- : 'Unable to mark an issue finding as resolved.', { cause });
3688
+ function addResolutionError(errors, destination, findingId, cause) {
3689
+ const semanticError = destination === 'pull request'
3690
+ ? (0, bugbot_mutation_error_1.bugbotMutationError)(cause, 'resolution', [findingId], 'mark-resolved')
3691
+ : new application_error_1.ApplicationError('provider.unavailable', 'Unable to mark an issue finding as resolved.');
3622
3692
  (0, logging_ports_1.logError)(semanticError);
3623
3693
  errors.push(semanticError);
3624
3694
  }
@@ -3867,6 +3937,7 @@ function isRecord(value) {
3867
3937
  */
3868
3938
  Object.defineProperty(exports, "__esModule", ({ value: true }));
3869
3939
  exports.publishFindings = publishFindings;
3940
+ const bugbot_mutation_error_1 = __nccwpck_require__(2937);
3870
3941
  const finding_1 = __nccwpck_require__(1011);
3871
3942
  const publish_issue_finding_comment_1 = __nccwpck_require__(4950);
3872
3943
  const publish_pr_review_comments_1 = __nccwpck_require__(352);
@@ -3885,12 +3956,17 @@ async function publishFindings(param) {
3885
3956
  catalog,
3886
3957
  })
3887
3958
  : undefined;
3888
- for (const finding of findings) {
3959
+ for (const finding of (0, finding_1.retainExistingFindingIds)(findings, existingByFindingId)) {
3889
3960
  if (operation.target.issueNumber > 0 && !reviewPublisher) {
3890
3961
  await (0, publish_issue_finding_comment_1.publishIssueFindingComment)(ports.issueComments, operation.target.issueNumber, finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding), commitSha, catalog);
3891
3962
  }
3892
3963
  if (reviewPublisher) {
3893
- await reviewPublisher.publish(finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding));
3964
+ try {
3965
+ await reviewPublisher.publish(finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding));
3966
+ }
3967
+ catch (cause) {
3968
+ throw (0, bugbot_mutation_error_1.bugbotMutationError)(cause, 'publication', [finding.id], 'publish-comments');
3969
+ }
3894
3970
  }
3895
3971
  }
3896
3972
  await reviewPublisher?.flush(overflowCount, overflowTitles);
@@ -3959,6 +4035,7 @@ ${catalog.message('bugbot.overflow.body', { count: `**${overflowCount}**` }, ove
3959
4035
 
3960
4036
  Object.defineProperty(exports, "__esModule", ({ value: true }));
3961
4037
  exports.PullRequestReviewCommentPublisher = void 0;
4038
+ const bugbot_mutation_error_1 = __nccwpck_require__(2937);
3962
4039
  const bugbot_finding_marker_policy_1 = __nccwpck_require__(8024);
3963
4040
  const path_validation_1 = __nccwpck_require__(124);
3964
4041
  const logging_ports_1 = __nccwpck_require__(6152);
@@ -4030,11 +4107,16 @@ class PullRequestReviewCommentPublisher {
4030
4107
  if (this.findingsToCreate.length === 0 && overflowCount === 0)
4031
4108
  return;
4032
4109
  const { repository, operation, openPrNumber, prContext } = this.options;
4033
- await repository.createReviewWithComments(openPrNumber, prContext.prHeadSha, buildReviewSummary(this.findingsToCreate, this.commentsToCreate.length, this.unanchoredBodies, overflowCount, overflowTitles, operation.analysis.reviewConfiguration.traceRules
4034
- ? this.options.ruleSources ?? []
4035
- : [], operation.analysis.reviewConfiguration.traceRules
4036
- ? this.options.omittedRuleCount ?? 0
4037
- : 0, prContext.prHeadSha, this.catalog), this.commentsToCreate);
4110
+ try {
4111
+ await repository.createReviewWithComments(openPrNumber, prContext.prHeadSha, buildReviewSummary(this.findingsToCreate, this.commentsToCreate.length, this.unanchoredBodies, overflowCount, overflowTitles, operation.analysis.reviewConfiguration.traceRules
4112
+ ? this.options.ruleSources ?? []
4113
+ : [], operation.analysis.reviewConfiguration.traceRules
4114
+ ? this.options.omittedRuleCount ?? 0
4115
+ : 0, prContext.prHeadSha, this.catalog), this.commentsToCreate);
4116
+ }
4117
+ catch (cause) {
4118
+ throw (0, bugbot_mutation_error_1.bugbotMutationError)(cause, 'publication', this.findingsToCreate.map(finding => finding.id), 'publish-comments', this.findingsToCreate.length + overflowCount);
4119
+ }
4038
4120
  }
4039
4121
  get catalog() {
4040
4122
  return this.options.catalog ?? (0, bugbot_message_catalog_1.resolveStaticBugbotCatalog)(this.options.operation.locale.pullRequest);
@@ -4188,6 +4270,8 @@ async function queryBugbotPartitionFindings(repository, configuration, prompt, t
4188
4270
 
4189
4271
  Object.defineProperty(exports, "__esModule", ({ value: true }));
4190
4272
  exports.reconcileBugbotReviewState = reconcileBugbotReviewState;
4273
+ const bugbot_mutation_error_1 = __nccwpck_require__(2937);
4274
+ const finding_1 = __nccwpck_require__(1011);
4191
4275
  const review_projection_1 = __nccwpck_require__(859);
4192
4276
  const bugbot_reconciliation_policy_1 = __nccwpck_require__(8128);
4193
4277
  const bugbot_provider_projection_policy_1 = __nccwpck_require__(5821);
@@ -4218,11 +4302,12 @@ async function reconcileBugbotReviewState(input) {
4218
4302
  };
4219
4303
  }
4220
4304
  const snapshot = snapshotResult.snapshot;
4305
+ const activeFindings = (0, finding_1.retainExistingFindingIds)(input.activeFindings, input.loadedContext.existingByFindingId);
4306
+ const expectedPublishedFindings = (0, finding_1.retainExistingFindingIds)(input.expectedPublishedFindings ?? input.activeFindings, input.loadedContext.existingByFindingId);
4221
4307
  const diagnostics = [
4222
- ...(input.mutationErrors ?? []).map((error) => ({
4223
- code: 'operation-failed',
4224
- operatorMessage: toSafeOperationMessage(error),
4225
- })),
4308
+ ...(input.mutationErrors ?? []).map((error) => error instanceof bugbot_mutation_error_1.BugbotMutationError
4309
+ ? { code: 'finding-mutation-failed', mutation: error.diagnostic }
4310
+ : { code: 'operation-failed', operatorMessage: toSafeOperationMessage(error) }),
4226
4311
  ...(!input.target.trustedAuthorLogin?.trim()
4227
4312
  ? [{ code: 'identity-unavailable' }]
4228
4313
  : []),
@@ -4231,7 +4316,7 @@ async function reconcileBugbotReviewState(input) {
4231
4316
  const providerProjection = (0, bugbot_provider_projection_policy_1.projectBugbotProviderEvidence)({
4232
4317
  snapshot,
4233
4318
  trustedAuthorLogin: input.target.trustedAuthorLogin,
4234
- activeFindings: input.activeFindings,
4319
+ activeFindings,
4235
4320
  existingByFindingId: input.loadedContext.existingByFindingId,
4236
4321
  });
4237
4322
  const plan = (0, bugbot_reconciliation_policy_1.buildBugbotReconciliationPlan)({
@@ -4241,8 +4326,8 @@ async function reconcileBugbotReviewState(input) {
4241
4326
  id,
4242
4327
  (0, bugbot_finding_marker_policy_1.extractTitleFromBody)(fullBody) || id,
4243
4328
  ])),
4244
- activeFindings: input.activeFindings,
4245
- expectedPublishedFindings: input.expectedPublishedFindings ?? input.activeFindings,
4329
+ activeFindings,
4330
+ expectedPublishedFindings,
4246
4331
  diagnostics,
4247
4332
  coverage: input.loadedContext.coverage,
4248
4333
  });
@@ -4697,14 +4782,16 @@ function toPresentationFailure(diagnostic) {
4697
4782
  const message = (0, bugbot_message_catalog_1.bugbotDiagnosticOperatorMessage)(diagnostic);
4698
4783
  return {
4699
4784
  diagnostic,
4700
- error: diagnostic.code === 'review-updates-pending'
4701
- ? new application_error_1.ApplicationError('workflow.presentation-pending', message, {
4702
- recovery: {
4703
- id: 'bugbot-review-blocks-pending',
4704
- variables: { pendingCount: diagnostic.count },
4705
- },
4706
- })
4707
- : new Error(message),
4785
+ error: diagnostic.code === 'finding-mutation-failed'
4786
+ ? new application_error_1.ApplicationError(diagnostic.mutation.errorCode, message)
4787
+ : diagnostic.code === 'review-updates-pending'
4788
+ ? new application_error_1.ApplicationError('workflow.presentation-pending', message, {
4789
+ recovery: {
4790
+ id: 'bugbot-review-blocks-pending',
4791
+ variables: { pendingCount: diagnostic.count },
4792
+ },
4793
+ })
4794
+ : new Error(message),
4708
4795
  };
4709
4796
  }
4710
4797
  function report(projection, reviewUpdates, pendingReviewUpdates, statusCardOperation, errors) {
@@ -5152,6 +5239,8 @@ var _ApplicationError_cause;
5152
5239
  Object.defineProperty(exports, "__esModule", ({ value: true }));
5153
5240
  exports.ApplicationError = exports.APPLICATION_ERROR_METADATA = exports.APPLICATION_ERROR_RECOVERY_IDS = void 0;
5154
5241
  exports.isApplicationErrorCorrelationId = isApplicationErrorCorrelationId;
5242
+ const closed_issue_reconciliation_1 = __nccwpck_require__(1565);
5243
+ const approval_evidence_diagnostic_1 = __nccwpck_require__(8205);
5155
5244
  const branch_sync_validation_1 = __nccwpck_require__(981);
5156
5245
  exports.APPLICATION_ERROR_RECOVERY_IDS = Object.freeze([
5157
5246
  'pull-request-link-restored',
@@ -5166,7 +5255,16 @@ exports.APPLICATION_ERROR_RECOVERY_IDS = Object.freeze([
5166
5255
  'branch-sync-resolution-invalid',
5167
5256
  'sdd-draft-size-exceeded',
5168
5257
  'sdd-draft-format-invalid',
5258
+ 'sdd-draft-case-identity-invalid',
5259
+ 'sdd-draft-case-budget-invalid',
5260
+ 'sdd-draft-requirement-mapping-invalid',
5261
+ 'sdd-draft-repository-path-invalid',
5169
5262
  'workspace-changes-rejected',
5263
+ 'closed-issue-reconciliation-failed',
5264
+ 'approval-evidence-read-failed',
5265
+ 'stored-configuration-schema-missing',
5266
+ 'stored-configuration-schema-unsupported',
5267
+ 'stored-configuration-invalid',
5170
5268
  ]);
5171
5269
  const PRESERVED_STATE = 'Existing persisted state and completed external effects were preserved.';
5172
5270
  const UNCHANGED_STATE = 'No new state or external effect was created.';
@@ -5358,6 +5456,11 @@ class ApplicationError extends Error {
5358
5456
  exports.ApplicationError = ApplicationError;
5359
5457
  _ApplicationError_cause = new WeakMap();
5360
5458
  const RECOVERY_VARIABLE_KEYS = Object.freeze({
5459
+ 'stored-configuration-schema-missing': Object.freeze(['issueNumber', 'expectedVersion']),
5460
+ 'stored-configuration-schema-unsupported': Object.freeze(['issueNumber', 'expectedVersion', 'actualVersion']),
5461
+ 'stored-configuration-invalid': Object.freeze(['issueNumber', 'expectedVersion']),
5462
+ 'closed-issue-reconciliation-failed': Object.freeze(['resultId', 'phase', 'state', 'reason', 'changed', 'remaining']),
5463
+ 'approval-evidence-read-failed': Object.freeze(['operation', 'reason', 'permission']),
5361
5464
  'pull-request-link-restored': Object.freeze([]),
5362
5465
  'pull-request-link-base-retained': Object.freeze([]),
5363
5466
  'pull-request-link-reference-retained': Object.freeze([]),
@@ -5370,6 +5473,10 @@ const RECOVERY_VARIABLE_KEYS = Object.freeze({
5370
5473
  'branch-sync-resolution-invalid': Object.freeze(['validationCode', 'command']),
5371
5474
  'sdd-draft-size-exceeded': Object.freeze([]),
5372
5475
  'sdd-draft-format-invalid': Object.freeze([]),
5476
+ 'sdd-draft-case-identity-invalid': Object.freeze([]),
5477
+ 'sdd-draft-case-budget-invalid': Object.freeze([]),
5478
+ 'sdd-draft-requirement-mapping-invalid': Object.freeze([]),
5479
+ 'sdd-draft-repository-path-invalid': Object.freeze([]),
5373
5480
  'workspace-changes-rejected': Object.freeze([]),
5374
5481
  });
5375
5482
  function normalizeApplicationErrorRecovery(recovery) {
@@ -5385,6 +5492,13 @@ function normalizeApplicationErrorRecovery(recovery) {
5385
5492
  || actualKeys.some((key, index) => key !== expectedKeys[index])) {
5386
5493
  throw new TypeError(`Application error recovery variables are invalid for ${recovery.id}.`);
5387
5494
  }
5495
+ if (recovery.id.startsWith('stored-configuration-')
5496
+ && (![variables.issueNumber, variables.expectedVersion].every(value => typeof value === 'number' && Number.isSafeInteger(value) && value > 0)
5497
+ || (recovery.id === 'stored-configuration-schema-unsupported'
5498
+ && !(typeof variables.actualVersion === 'number'
5499
+ && Number.isSafeInteger(variables.actualVersion) && variables.actualVersion >= 0)))) {
5500
+ throw new TypeError('Stored configuration diagnostic is invalid.');
5501
+ }
5388
5502
  if (recovery.id === 'managed-branch-enrichment-failed'
5389
5503
  && (typeof variables.branchName !== 'string'
5390
5504
  || !/^[A-Za-z0-9][A-Za-z0-9._/-]{0,254}$/u.test(variables.branchName))) {
@@ -5410,6 +5524,20 @@ function normalizeApplicationErrorRecovery(recovery) {
5410
5524
  && !branch_sync_validation_1.BRANCH_SYNC_VALIDATION_CODES.some(code => code === variables.validationCode)) {
5411
5525
  throw new TypeError('Application error recovery synchronization validation code is invalid.');
5412
5526
  }
5527
+ if (recovery.id === 'closed-issue-reconciliation-failed'
5528
+ && (!closed_issue_reconciliation_1.CLOSED_ISSUE_RESULTS.some(value => value === variables.resultId)
5529
+ || !closed_issue_reconciliation_1.CLOSED_ISSUE_PHASES.some(value => value === variables.phase)
5530
+ || !['open', 'closed', 'unavailable'].includes(variables.state)
5531
+ || !closed_issue_reconciliation_1.CLOSED_ISSUE_REASONS.some(value => value === variables.reason)
5532
+ || ![variables.changed, variables.remaining].every(value => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 && value <= 3000))) {
5533
+ throw new TypeError('Closed issue reconciliation diagnostic is invalid.');
5534
+ }
5535
+ if (recovery.id === 'approval-evidence-read-failed'
5536
+ && (!Object.prototype.hasOwnProperty.call(approval_evidence_diagnostic_1.APPROVAL_EVIDENCE_PERMISSIONS, variables.operation)
5537
+ || !approval_evidence_diagnostic_1.APPROVAL_EVIDENCE_REASONS.some(reason => reason === variables.reason)
5538
+ || approval_evidence_diagnostic_1.APPROVAL_EVIDENCE_PERMISSIONS[variables.operation] !== variables.permission)) {
5539
+ throw new TypeError('Approval evidence diagnostic is invalid.');
5540
+ }
5413
5541
  return Object.freeze({
5414
5542
  id: recovery.id,
5415
5543
  variables: Object.freeze({ ...variables }),
@@ -5468,6 +5596,43 @@ function isAgentConfigurationReady(configuration) {
5468
5596
  }
5469
5597
 
5470
5598
 
5599
+ /***/ }),
5600
+
5601
+ /***/ 8205:
5602
+ /***/ ((__unused_webpack_module, exports) => {
5603
+
5604
+
5605
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
5606
+ exports.APPROVAL_EVIDENCE_REASONS = exports.APPROVAL_EVIDENCE_PERMISSIONS = void 0;
5607
+ /** Closed vocabulary: no provider text, URLs, headers, policy values or credentials. */
5608
+ exports.APPROVAL_EVIDENCE_PERMISSIONS = Object.freeze({
5609
+ 'evidence': 'repository-read',
5610
+ 'pull-request': 'pull-requests-read',
5611
+ 'base-ref': 'contents-read',
5612
+ 'merge-commit': 'contents-read',
5613
+ 'policy': 'actions-variables-read',
5614
+ 'files': 'pull-requests-read',
5615
+ 'reviews': 'pull-requests-read',
5616
+ 'comments': 'issues-read',
5617
+ 'head-checks': 'checks-read',
5618
+ 'merge-checks': 'checks-read',
5619
+ 'head-runs': 'actions-read',
5620
+ 'merge-runs': 'actions-read',
5621
+ 'jobs': 'actions-read',
5622
+ 'rules': 'metadata-read',
5623
+ 'classic-protection': 'administration-read',
5624
+ 'authenticated-user': 'authenticated-user-read',
5625
+ 'coverage-artifacts': 'actions-read',
5626
+ 'coverage-download': 'actions-read',
5627
+ 'coverage-parse': 'actions-read',
5628
+ });
5629
+ exports.APPROVAL_EVIDENCE_REASONS = Object.freeze([
5630
+ 'http-400', 'http-401', 'http-403', 'http-404', 'http-409', 'http-422', 'http-429',
5631
+ 'http-500', 'http-502', 'http-503', 'http-504', 'transport-unavailable',
5632
+ 'invalid-response', 'invalid-page', 'page-limit', 'artifact-unavailable', 'artifact-invalid', 'artifact-mismatch',
5633
+ ]);
5634
+
5635
+
5471
5636
  /***/ }),
5472
5637
 
5473
5638
  /***/ 981:
@@ -5585,9 +5750,14 @@ function matchesConstrainedHead(target, candidate) {
5585
5750
  /***/ }),
5586
5751
 
5587
5752
  /***/ 1011:
5588
- /***/ ((__unused_webpack_module, exports) => {
5753
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
5589
5754
 
5590
5755
 
5756
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
5757
+ exports.isExistingFindingFullyResolved = isExistingFindingFullyResolved;
5758
+ exports.findExistingFindingInfo = findExistingFindingInfo;
5759
+ exports.findExistingFindingMatch = findExistingFindingMatch;
5760
+ exports.retainExistingFindingIds = retainExistingFindingIds;
5591
5761
  /**
5592
5762
  * Provider-neutral Bugbot finding and durable identity contracts.
5593
5763
  *
@@ -5595,9 +5765,7 @@ function matchesConstrainedHead(target, candidate) {
5595
5765
  * them in the domain prevents policies from depending on a particular use-case
5596
5766
  * folder and gives every adapter one stable semantic vocabulary.
5597
5767
  */
5598
- Object.defineProperty(exports, "__esModule", ({ value: true }));
5599
- exports.isExistingFindingFullyResolved = isExistingFindingFullyResolved;
5600
- exports.findExistingFindingInfo = findExistingFindingInfo;
5768
+ const finding_identity_1 = __nccwpck_require__(1853);
5601
5769
  function isExistingFindingFullyResolved(finding) {
5602
5770
  const destinations = [finding.issue, finding.pullRequest].filter((destination) => destination != null);
5603
5771
  return (destinations.length > 0 &&
@@ -5605,21 +5773,62 @@ function isExistingFindingFullyResolved(finding) {
5605
5773
  finding.pullRequest?.verificationRequired !== true);
5606
5774
  }
5607
5775
  function findExistingFindingInfo(existingByFindingId, finding) {
5776
+ return findExistingFindingMatch(existingByFindingId, finding)?.info;
5777
+ }
5778
+ /** A match carries its durable key so updating a comment cannot re-key it. */
5779
+ function findExistingFindingMatch(existingByFindingId, finding) {
5608
5780
  const direct = existingByFindingId[finding.id];
5609
5781
  if (direct && identitiesAreCompatible(direct, finding))
5610
- return direct;
5611
- const candidates = Object.values(existingByFindingId);
5782
+ return { id: finding.id, info: direct };
5783
+ const candidates = Object.entries(existingByFindingId);
5612
5784
  if (finding.fingerprint) {
5613
- const locationMatch = candidates.find((candidate) => candidate.issue?.fingerprint === finding.fingerprint
5785
+ const locationMatches = candidates.filter(([, candidate]) => candidate.issue?.fingerprint === finding.fingerprint
5614
5786
  || candidate.pullRequest?.fingerprint === finding.fingerprint);
5615
- if (locationMatch)
5616
- return locationMatch;
5787
+ if (locationMatches.length > 0)
5788
+ return uniqueFindingMatch(locationMatches);
5617
5789
  }
5618
5790
  if (!finding.semanticFingerprint)
5619
5791
  return undefined;
5620
- const semanticMatches = candidates.filter((candidate) => candidate.issue?.semanticFingerprint === finding.semanticFingerprint
5792
+ const semanticMatches = candidates.filter(([, candidate]) => candidate.issue?.semanticFingerprint === finding.semanticFingerprint
5621
5793
  || candidate.pullRequest?.semanticFingerprint === finding.semanticFingerprint);
5622
- return semanticMatches.length === 1 ? semanticMatches[0] : undefined;
5794
+ return uniqueFindingMatch(semanticMatches);
5795
+ }
5796
+ /**
5797
+ * Preserve trusted IDs across title/location changes, before limits, publication
5798
+ * and final projection. Multiple reports of one uniquely matched durable finding
5799
+ * share one record; unmatched or ambiguous reports remain independent evidence.
5800
+ */
5801
+ function retainExistingFindingIds(findings, existingByFindingId) {
5802
+ const retained = new Set();
5803
+ const durableIds = new Set(Object.keys(existingByFindingId));
5804
+ // Reserve the whole input up front so a generated ID cannot take another
5805
+ // report's ID, including one that occurs later in the response.
5806
+ const reservedIds = new Set([...durableIds, ...findings.map((finding) => finding.id)]);
5807
+ const emittedIds = new Set();
5808
+ return findings.flatMap((finding) => {
5809
+ const match = findExistingFindingMatch(existingByFindingId, finding);
5810
+ if (!match) {
5811
+ let id = finding.id;
5812
+ if (durableIds.has(id) || emittedIds.has(id)) {
5813
+ const base = `candidate-${(0, finding_identity_1.buildFindingFingerprint)(finding)}`;
5814
+ id = base;
5815
+ let suffix = 0;
5816
+ while (reservedIds.has(id))
5817
+ id = `${base}-${++suffix}`;
5818
+ reservedIds.add(id);
5819
+ }
5820
+ emittedIds.add(id);
5821
+ return [id === finding.id ? finding : { ...finding, id }];
5822
+ }
5823
+ if (retained.has(match.id))
5824
+ return [];
5825
+ retained.add(match.id);
5826
+ emittedIds.add(match.id);
5827
+ return [finding.id === match.id ? finding : { ...finding, id: match.id }];
5828
+ });
5829
+ }
5830
+ function uniqueFindingMatch(matches) {
5831
+ return matches.length === 1 ? { id: matches[0][0], info: matches[0][1] } : undefined;
5623
5832
  }
5624
5833
  function identitiesAreCompatible(existing, finding) {
5625
5834
  const existingFingerprints = [
@@ -5913,6 +6122,24 @@ function countActionableBugbotFindings(counts) {
5913
6122
  }
5914
6123
 
5915
6124
 
6125
+ /***/ }),
6126
+
6127
+ /***/ 1565:
6128
+ /***/ ((__unused_webpack_module, exports) => {
6129
+
6130
+
6131
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
6132
+ exports.CLOSED_ISSUE_REASONS = exports.CLOSED_ISSUE_PHASES = exports.CLOSED_ISSUE_RESULTS = void 0;
6133
+ exports.CLOSED_ISSUE_RESULTS = Object.freeze([
6134
+ 'ReconcileClosedIssueMetadataUseCase', 'CloseIssueAfterMergingUseCase', 'RetireBranchSyncUseCase', 'RetireProgressUseCase',
6135
+ ]);
6136
+ exports.CLOSED_ISSUE_PHASES = Object.freeze([
6137
+ 'identity', 'read', 'native-fence', 'label-remove', 'label-add', 'metadata-verification',
6138
+ 'card-inventory', 'card-freshness', 'card-update', 'card-verification',
6139
+ ]);
6140
+ exports.CLOSED_ISSUE_REASONS = Object.freeze(['completed', 'not_planned', 'duplicate', 'reopened', 'unknown', 'unavailable']);
6141
+
6142
+
5916
6143
  /***/ }),
5917
6144
 
5918
6145
  /***/ 8623:
@@ -6464,11 +6691,13 @@ function getAnswerIssueHelpPrompt(params) {
6464
6691
 
6465
6692
 
6466
6693
  Object.defineProperty(exports, "__esModule", ({ value: true }));
6694
+ exports.BUGBOT_FINDING_GROUNDING_INSTRUCTION = void 0;
6467
6695
  exports.getBugbotPrompt = getBugbotPrompt;
6468
6696
  /**
6469
6697
  * Prompt for Bugbot detection (detect potential problems on push).
6470
6698
  */
6471
6699
  const fill_1 = __nccwpck_require__(2559);
6700
+ exports.BUGBOT_FINDING_GROUNDING_INSTRUCTION = 'Before returning a finding, try to disprove it against the exact reviewed source. Read effective repository configuration and inherited library/protocol defaults before inferring behavior from a missing command flag. Trace short-circuit guards, validation helpers and the actual caller/render path before claiming that an unsafe branch is reachable or that separate call sites coexist. Recompute arithmetic and check cited line numbers against the current file/diff. If your evidence refutes the alleged defect, withdraw the finding entirely; do not publish a contradictory or self-refuting report. These checks apply equally to low/info severity. Report a confirmed failure when those protections are absent; do not assume they exist.';
6472
6701
  const TEMPLATE = `You are analyzing the latest code changes for potential bugs and issues.
6473
6702
 
6474
6703
  Write every human-readable finding title, description, evidence, and suggestion in {{targetLocale}}. Preserve identifiers, code, symbols, paths, refs, commands, and URLs verbatim. Echo \`outputLocale\` exactly as \`{{targetLocale}}\`.
@@ -6504,6 +6733,8 @@ For every finding:
6504
6733
  - include the nearest stable \`symbol\` and a minimal exact \`codeSnippet\` when available so the finding can survive rebases, line movement, and file renames.
6505
6734
  - when a fix is a safe replacement of exactly the reported line range, include only the replacement text in \`suggestedCode\`; otherwise omit it.
6506
6735
 
6736
+ ${exports.BUGBOT_FINDING_GROUNDING_INSTRUCTION}
6737
+
6507
6738
  Return every finding field required by the response schema. Use null for file, line, endLine, severity, confidence, category, evidence, suggestion, symbol, codeSnippet, or suggestedCode when that value does not safely apply. Only include files outside the ignore list.
6508
6739
  {{previousBlock}}
6509
6740