@yemi33/minions 0.1.2090 → 0.1.2091

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.
Files changed (2) hide show
  1. package/engine.js +57 -1
  2. package/package.json +1 -1
package/engine.js CHANGED
@@ -4816,7 +4816,28 @@ async function discoverFromPrs(config, project) {
4816
4816
  }
4817
4817
  const autoFixBuilds = config.engine?.autoFixBuilds ?? ENGINE_DEFAULTS.autoFixBuilds;
4818
4818
  if (pollEnabled && autoFixBuilds && pr.status === PR_STATUS.ACTIVE && pr.buildStatus === 'failing'
4819
+ && !fixDispatched
4819
4820
  && !isPrNoOpFixCauseSuppressed(pr, shared.PR_FIX_CAUSE.BUILD_FAILURE)) {
4821
+ // W-mpritzcr0004afc5 (#2955): "don't fan out a parallel build-failure
4822
+ // fix while the review-feedback path owns the PR" — implemented via
4823
+ // the `!fixDispatched` gate above (mirrors the merge-conflict block
4824
+ // below). This preserves W-mphnm6a1000281b8 / PR #57 starvation fix:
4825
+ // when the review-feedback dispatch is suppressed by its own cooldown,
4826
+ // `fixDispatched` stays false and the build-fix path still gets to
4827
+ // run. An earlier draft used a bare `reviewStatus === 'changes-requested'`
4828
+ // skip, which broke that starvation guarantee.
4829
+ //
4830
+ // W-mpritzcr0004afc5 (#2955): receive-side cap from lifecycle.js
4831
+ // (`updatePrAfterFix` BUILD_FAILURE branch) flagged this PR as
4832
+ // unrecoverable by auto-retry after `engine.maxBuildFixRetries`
4833
+ // consecutive unverified pushes. Honor the flag here so the dispatcher
4834
+ // stops queuing fix agents — a human must inspect the worktree or
4835
+ // branch protection. Cleared by the same lifecycle path on the next
4836
+ // verified push (lifecycle.js:~2184).
4837
+ if (pr._buildFixNeedsHumanRebase) {
4838
+ log('info', `Skipping build-fix for ${pr.id}: _buildFixNeedsHumanRebase is set — engine reached maxBuildFixRetries, awaiting human rescue`);
4839
+ continue;
4840
+ }
4820
4841
  // P-b7e1c4d2: skip when the most recent BUILD-FAILURE dispatch already
4821
4842
  // noop'd against the same head SHA — chronic across PRs #2315–#2323
4822
4843
  // where every fix agent rebutted "this is a pre-existing master baseline"
@@ -4907,8 +4928,16 @@ async function discoverFromPrs(config, project) {
4907
4928
  if (!prBranch) continue;
4908
4929
 
4909
4930
  const reviewNote = [
4931
+ `Cause: ${shared.PR_FIX_CAUSE.BUILD_FAILURE}.`,
4910
4932
  `Build is failing: ${pr.buildFailReason || 'check CI pipeline for details'}.`,
4911
4933
  'Inspect the live PR checks/build logs yourself, decide the root cause, fix it, run the relevant local validation, and push.',
4934
+ // W-mpritzcr0004afc5 (#2955): the engine-fetched build error log on the
4935
+ // PR record is intentionally not inlined here — the build-error-log
4936
+ // feature regression test in test/unit/build-error-log-feature.test.js
4937
+ // locks the "let the agent inspect live CI" design so the engine does
4938
+ // not have to stay in sync with each CI provider's log format. The
4939
+ // Cause label above plus the build-fail reason is enough to disambiguate
4940
+ // this dispatch from review-feedback / merge-conflict triggers.
4912
4941
  pr.url ? `PR URL: ${pr.url}` : '',
4913
4942
  ].filter(Boolean).join('\n');
4914
4943
 
@@ -4949,8 +4978,30 @@ async function discoverFromPrs(config, project) {
4949
4978
  const autoFixConflicts = config.engine?.autoFixConflicts ?? ENGINE_DEFAULTS.autoFixConflicts;
4950
4979
  if (pollEnabled && autoFixConflicts && pr.status === PR_STATUS.ACTIVE && pr._mergeConflict && !fixDispatched
4951
4980
  && !isPrNoOpFixCauseSuppressed(pr, shared.PR_FIX_CAUSE.MERGE_CONFLICT)) {
4981
+ // W-mpritzcr0004afc5 (#2955): "don't fan out a parallel conflict-fix
4982
+ // while the review-feedback path owns the PR" is already handled by
4983
+ // the existing `!fixDispatched` gate above. When review-feedback is
4984
+ // queued in this same iteration, fixDispatched=true and this block
4985
+ // skips. When review-feedback is suppressed by its own cooldown, this
4986
+ // block can still fire — preserving the W-mphnm6a1000281b8 / PR #57
4987
+ // starvation guarantee.
4952
4988
  const conflictCauseKey = getPrAutomationCauseKey('merge-conflict', pr);
4953
4989
  const key = getPrAutomationDispatchKey(`conflict-fix-${project?.name || 'default'}-${prDisplayId}`, conflictCauseKey);
4990
+ // W-mpritzcr0004afc5 (#2955): per-cause same-head guard mirroring the
4991
+ // build-failure block above. `_conflictFixedAt` is a 10-min wall-clock
4992
+ // suppression for ADO/GH mergeStatus lag; `_lastDispatchByCause` is a
4993
+ // headSha-pinned suppression for repeated agent noops on an unchanged
4994
+ // base+head pair. Both must fire (their windows are independent).
4995
+ const currentHeadSha = String(pr.headSha || pr._adoSourceCommit || pr._adoHeadCommit || '').trim();
4996
+ const lastConflictDispatch = pr._lastDispatchByCause?.[shared.PR_FIX_CAUSE.MERGE_CONFLICT];
4997
+ const skipConflictFix = !!(lastConflictDispatch?.outcome === 'noop'
4998
+ && lastConflictDispatch.headSha
4999
+ && currentHeadSha
5000
+ && lastConflictDispatch.headSha === currentHeadSha);
5001
+ if (skipConflictFix) {
5002
+ log('info', `Skipping conflict-fix for ${pr.id}: last merge-conflict dispatch was noop on the same head ${currentHeadSha.slice(0, 8)} (${(lastConflictDispatch.reason || '').slice(0, 120)})`);
5003
+ continue;
5004
+ }
4954
5005
  // Suppress re-dispatch for 10 min after last attempt — ADO/GitHub recomputes
4955
5006
  // mergeStatus asynchronously (1–5 min lag), so the flag may stay set even after
4956
5007
  // a successful push. _conflictFixedAt is cleared when the poller confirms clean status.
@@ -4985,9 +5036,14 @@ async function discoverFromPrs(config, project) {
4985
5036
  if (agentId) {
4986
5037
  const prBranch = ensurePrBranchForDispatch(project, pr, 'conflict-fix');
4987
5038
  if (!prBranch) continue;
5039
+ const conflictReviewNote = [
5040
+ `Cause: ${shared.PR_FIX_CAUSE.MERGE_CONFLICT}.`,
5041
+ 'This PR has merge conflicts with the target branch. Inspect the live PR and repository history, choose the safest merge/rebase/update strategy, resolve all conflicts, validate the result, and push the branch.',
5042
+ pr.url ? `PR URL: ${pr.url}` : '',
5043
+ ].filter(Boolean).join('\n');
4988
5044
  const item = buildPrDispatch(agentId, config, project, pr, 'fix', {
4989
5045
  pr_id: pr.id, pr_branch: prBranch,
4990
- review_note: `This PR has merge conflicts with the target branch. Inspect the live PR and repository history, choose the safest merge/rebase/update strategy, resolve all conflicts, validate the result, and push the branch.`,
5046
+ review_note: conflictReviewNote,
4991
5047
  }, `Fix merge conflicts on ${pr.id}: ${pr.title || ''}`, { dispatchKey: key, cooldownKey: key, automationCauseKey: conflictCauseKey, source: 'pr', pr, branch: prBranch, project: projMeta });
4992
5048
  if (item) {
4993
5049
  newWork.push(item);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2090",
3
+ "version": "0.1.2091",
4
4
  "description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
5
5
  "bin": {
6
6
  "minions": "bin/minions.js"