@yemi33/minions 0.1.1905 → 0.1.1906

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.
@@ -0,0 +1,5 @@
1
+ {
2
+ "runtime": "copilot",
3
+ "models": null,
4
+ "cachedAt": "2026-05-12T20:22:16.745Z"
5
+ }
@@ -1847,15 +1847,32 @@ function recordPrNoOpFixAttempt(target, cause, source, dispatchItem, branchChang
1847
1847
  // filter can short-circuit duplicate build-fix dispatches against an
1848
1848
  // unchanged commit. Reset happens implicitly when headSha advances and the
1849
1849
  // discovery filter compares lastDispatchHeadSha to the current head.
1850
+ //
1851
+ // Tracking is partitioned by cause (`_lastDispatchByCause[cause]`) so a
1852
+ // human-feedback noop on head X never suppresses an unrelated build-failure
1853
+ // dispatch on head X (the PR-wide top-level fields would, see
1854
+ // W-mp2vohea00112739). The legacy top-level fields are kept in sync for
1855
+ // any external consumer (dashboards, debugging) but the build-fix
1856
+ // eligibility filter reads ONLY the per-cause map.
1850
1857
  const headSha = getPrFixBaselineHead(target);
1851
- target.lastDispatchedAt = now;
1852
- target.lastDispatchOutcome = 'noop';
1853
- target.lastDispatchHeadSha = headSha;
1854
- target.lastDispatchReason = String(
1858
+ const reasonText = String(
1855
1859
  noopReason
1856
1860
  || branchChange?.reason
1857
1861
  || 'fix completed without changing the PR branch'
1858
1862
  ).slice(0, 500);
1863
+ target._lastDispatchByCause = target._lastDispatchByCause
1864
+ && typeof target._lastDispatchByCause === 'object' ? target._lastDispatchByCause : {};
1865
+ target._lastDispatchByCause[cause] = {
1866
+ outcome: 'noop',
1867
+ headSha,
1868
+ reason: reasonText,
1869
+ dispatchedAt: now,
1870
+ dispatchId: dispatchItem?.id || null,
1871
+ };
1872
+ target.lastDispatchedAt = now;
1873
+ target.lastDispatchOutcome = 'noop';
1874
+ target.lastDispatchHeadSha = headSha;
1875
+ target.lastDispatchReason = reasonText;
1859
1876
 
1860
1877
  if (cause === shared.PR_FIX_CAUSE.HUMAN_FEEDBACK && target.humanFeedback) {
1861
1878
  target.humanFeedback.pendingFix = !paused;
@@ -1877,10 +1894,19 @@ function clearPrNoOpFixAttempt(target, cause) {
1877
1894
  // the same head; once the agent actually pushed a fix we no longer want them
1878
1895
  // to suppress a fresh dispatch (the SHA may have moved or the next failure
1879
1896
  // is genuinely new).
1880
- delete target.lastDispatchedAt;
1881
- delete target.lastDispatchOutcome;
1882
- delete target.lastDispatchHeadSha;
1883
- delete target.lastDispatchReason;
1897
+ if (target._lastDispatchByCause && typeof target._lastDispatchByCause === 'object') {
1898
+ delete target._lastDispatchByCause[cause];
1899
+ if (Object.keys(target._lastDispatchByCause).length === 0) delete target._lastDispatchByCause;
1900
+ }
1901
+ // Only clear the legacy top-level fields when no other cause still has a
1902
+ // tracked noop — otherwise a successful fix for cause A would silently wipe
1903
+ // out the same-head suppression record for unrelated cause B.
1904
+ if (!target._lastDispatchByCause) {
1905
+ delete target.lastDispatchedAt;
1906
+ delete target.lastDispatchOutcome;
1907
+ delete target.lastDispatchHeadSha;
1908
+ delete target.lastDispatchReason;
1909
+ }
1884
1910
  }
1885
1911
 
1886
1912
  function updatePrAfterFix(pr, project, source, options = {}, legacyDispatchId = '') {
package/engine.js CHANGED
@@ -2971,18 +2971,25 @@ async function discoverFromPrs(config, project) {
2971
2971
  const autoFixBuilds = config.engine?.autoFixBuilds ?? ENGINE_DEFAULTS.autoFixBuilds;
2972
2972
  if (pollEnabled && autoFixBuilds && pr.status === PR_STATUS.ACTIVE && pr.buildStatus === 'failing'
2973
2973
  && !isPrNoOpFixCauseSuppressed(pr, shared.PR_FIX_CAUSE.BUILD_FAILURE)) {
2974
- // P-b7e1c4d2: skip when the most recent dispatch already noop'd against
2975
- // the same head SHA — chronic across PRs #2315–#2323 where every fix
2976
- // agent rebutted "this is a pre-existing master baseline" but the
2977
- // cached buildStatus:failing kept re-triggering the loop. The check
2978
- // clears automatically once a new commit lands (lastDispatchHeadSha
2979
- // stops matching the current head).
2974
+ // P-b7e1c4d2: skip when the most recent BUILD-FAILURE dispatch already
2975
+ // noop'd against the same head SHA — chronic across PRs #2315–#2323
2976
+ // where every fix agent rebutted "this is a pre-existing master baseline"
2977
+ // but the cached buildStatus:failing kept re-triggering the loop. The
2978
+ // check clears automatically once a new commit lands (the per-cause
2979
+ // headSha stops matching the current head).
2980
+ //
2981
+ // W-mp2vohea00112739: this guard reads `_lastDispatchByCause['build-failure']`
2982
+ // instead of the PR-wide `lastDispatch*` fields. The PR-wide fields are
2983
+ // shared across all causes, so a `human-feedback` noop on head X used to
2984
+ // suppress an unrelated `build-failure` dispatch on the same head until
2985
+ // a new commit landed (live repro on PR #2433).
2980
2986
  const currentHeadSha = String(pr.headSha || pr._adoSourceCommit || pr._adoHeadCommit || '').trim();
2981
- if (pr.lastDispatchOutcome === 'noop'
2982
- && pr.lastDispatchHeadSha
2987
+ const lastBuildDispatch = pr._lastDispatchByCause?.[shared.PR_FIX_CAUSE.BUILD_FAILURE];
2988
+ if (lastBuildDispatch?.outcome === 'noop'
2989
+ && lastBuildDispatch.headSha
2983
2990
  && currentHeadSha
2984
- && pr.lastDispatchHeadSha === currentHeadSha) {
2985
- log('info', `Skipping build-fix for ${pr.id}: last dispatch was noop on the same head ${currentHeadSha.slice(0, 8)} (${(pr.lastDispatchReason || '').slice(0, 120)})`);
2991
+ && lastBuildDispatch.headSha === currentHeadSha) {
2992
+ log('info', `Skipping build-fix for ${pr.id}: last build-failure dispatch was noop on the same head ${currentHeadSha.slice(0, 8)} (${(lastBuildDispatch.reason || '').slice(0, 120)})`);
2986
2993
  continue;
2987
2994
  }
2988
2995
  const buildCauseKey = getPrAutomationCauseKey('build', pr);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1905",
3
+ "version": "0.1.1906",
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"