@yemi33/minions 0.1.2101 → 0.1.2102
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.
- package/docs/pr-review-fix-loop.md +2 -2
- package/engine/ado.js +21 -0
- package/engine/github.js +21 -0
- package/engine/lifecycle.js +35 -0
- package/engine/shared.js +9 -11
- package/package.json +1 -1
|
@@ -75,11 +75,11 @@ Each fix cause (build-failure, review-feedback, human-feedback, merge-conflict,
|
|
|
75
75
|
|
|
76
76
|
A paused cause **suppresses further auto-dispatch for that cause** until cleared. Recovery paths (any one):
|
|
77
77
|
|
|
78
|
-
1. **Push a new SHA to the PR branch** — the next poll refreshes `pr.headSha`, the evidence fingerprint shifts, and `clearPrNoOpFixAttempt` runs on the next non-noop completion.
|
|
78
|
+
1. **Push a new SHA to the PR branch** — the next poll refreshes `pr.headSha`, the evidence fingerprint shifts, and `clearPrNoOpFixAttempt` runs on the next non-noop completion. Since #2979 (head-SHA in BUILD_FAILURE + REVIEW_FEEDBACK fingerprints) and W-mpx44p05000ze8d8 (proactive GC sweep in `pollPrStatus`), a force-push also drops the stale `_noOpFixes[cause]` record on the next poll — the dashboard `_pausedCauses` chip clears without waiting for a fresh fix dispatch.
|
|
79
79
|
2. **Click the red chip on the dashboard** — confirms, then `POST /api/pull-requests/clear-paused-cause` (`dashboard.js`, issue #2969) validates the cause against `shared.PR_FIX_CAUSE`, locates the PR via `mutatePullRequests` across project/central files, and calls `clearPrNoOpFixAttempt` to wipe the cause record.
|
|
80
80
|
3. **Direct API call** — `POST /api/pull-requests/clear-paused-cause` with `{ prId, cause }`.
|
|
81
81
|
|
|
82
|
-
The exported `recordPrNoOpFixAttempt` / `clearPrNoOpFixAttempt` helpers in `engine/lifecycle.js` are the only sanctioned entry points
|
|
82
|
+
The exported `recordPrNoOpFixAttempt` / `clearPrNoOpFixAttempt` / `sweepStalePrNoOpFixes` helpers in `engine/lifecycle.js` are the only sanctioned entry points. The dispatch evaluator gates re-dispatch on `shared.isPrNoOpFixCausePaused(pr, cause)` (which re-validates the fingerprint per call), the dashboard chip surface uses `shared.getPrPausedCauses(pr)` (same gate), and the `pollPrStatus` callback in `engine/ado.js` + `engine/github.js` calls `sweepStalePrNoOpFixes(pr)` each tick to GC records whose fingerprint no longer matches the live PR.
|
|
83
83
|
|
|
84
84
|
## 5. Fix completes
|
|
85
85
|
|
package/engine/ado.js
CHANGED
|
@@ -24,6 +24,12 @@ function engine() {
|
|
|
24
24
|
let _dispatch = null;
|
|
25
25
|
function dispatchModule() { if (!_dispatch) _dispatch = require('./dispatch'); return _dispatch; }
|
|
26
26
|
|
|
27
|
+
// Lazy require for lifecycle module — only needed for the stale-noopfix sweep
|
|
28
|
+
// in pollPrStatus (W-mpx44p05000ze8d8). lifecycle.js lazy-requires ado.js back,
|
|
29
|
+
// so this MUST stay lazy to avoid a circular import at module-load time.
|
|
30
|
+
let _lifecycle = null;
|
|
31
|
+
function lifecycleModule() { if (!_lifecycle) _lifecycle = require('./lifecycle'); return _lifecycle; }
|
|
32
|
+
|
|
27
33
|
const stripRefsHeads = s => (s || '').replace('refs/heads/', '');
|
|
28
34
|
const getAdoPrUrl = (project, prNumber) => {
|
|
29
35
|
if (project.prUrlBase) return `${project.prUrlBase}${prNumber}`;
|
|
@@ -1476,6 +1482,21 @@ async function pollPrStatus(config) {
|
|
|
1476
1482
|
updated = true;
|
|
1477
1483
|
}
|
|
1478
1484
|
|
|
1485
|
+
// W-mpx44p05000ze8d8 — Proactive GC for stale `_noOpFixes` records. Any
|
|
1486
|
+
// cause whose stored evidence fingerprint no longer matches the live PR
|
|
1487
|
+
// (head SHA shifted, build failure reason changed, new human comment,
|
|
1488
|
+
// review status flipped, etc.) is dropped via clearPrNoOpFixAttempt. The
|
|
1489
|
+
// dispatch gate already ignores these stale records (isPrNoOpFixCausePaused
|
|
1490
|
+
// re-validates the fingerprint), but without this sweep they linger in
|
|
1491
|
+
// pull-requests.json forever — bloating the file and confusing the
|
|
1492
|
+
// dashboard `pr-paused-chip`. Runs AFTER all live-field updates so the
|
|
1493
|
+
// fingerprint comparison uses post-poll PR state.
|
|
1494
|
+
try {
|
|
1495
|
+
if (lifecycleModule().sweepStalePrNoOpFixes(pr)) updated = true;
|
|
1496
|
+
} catch (e) {
|
|
1497
|
+
log('warn', `sweepStalePrNoOpFixes for ${pr.id}: ${e.message}`);
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1479
1500
|
return updated;
|
|
1480
1501
|
} catch (err) {
|
|
1481
1502
|
// Auth errors → mark build status stale so dashboard shows uncertainty
|
package/engine/github.js
CHANGED
|
@@ -23,6 +23,12 @@ function engine() {
|
|
|
23
23
|
let _dispatch = null;
|
|
24
24
|
function dispatchModule() { if (!_dispatch) _dispatch = require('./dispatch'); return _dispatch; }
|
|
25
25
|
|
|
26
|
+
// Lazy require for lifecycle module — only needed for the stale-noopfix sweep
|
|
27
|
+
// in pollPrStatus (W-mpx44p05000ze8d8). lifecycle.js lazy-requires github.js
|
|
28
|
+
// back, so this MUST stay lazy to avoid a circular import at module-load time.
|
|
29
|
+
let _lifecycle = null;
|
|
30
|
+
function lifecycleModule() { if (!_lifecycle) _lifecycle = require('./lifecycle'); return _lifecycle; }
|
|
31
|
+
|
|
26
32
|
// W-mp5trwh60008386d: test seam so unit tests can mock `gh api` shell-outs
|
|
27
33
|
// without spawning the real CLI. Production code goes through the real
|
|
28
34
|
// `execAsync` from shared; tests call `_setExecAsyncForTest(fn)` to swap in
|
|
@@ -1021,6 +1027,21 @@ async function pollPrStatus(config) {
|
|
|
1021
1027
|
}
|
|
1022
1028
|
}
|
|
1023
1029
|
|
|
1030
|
+
// W-mpx44p05000ze8d8 — Proactive GC for stale `_noOpFixes` records. Any
|
|
1031
|
+
// cause whose stored evidence fingerprint no longer matches the live PR
|
|
1032
|
+
// (head SHA shifted, build failure reason changed, new human comment,
|
|
1033
|
+
// review status flipped, etc.) is dropped via clearPrNoOpFixAttempt. The
|
|
1034
|
+
// dispatch gate already ignores these stale records (isPrNoOpFixCausePaused
|
|
1035
|
+
// re-validates the fingerprint), but without this sweep they linger in
|
|
1036
|
+
// pull-requests.json forever — bloating the file and confusing the
|
|
1037
|
+
// dashboard `pr-paused-chip`. Runs AFTER all live-field updates so the
|
|
1038
|
+
// fingerprint comparison uses post-poll PR state.
|
|
1039
|
+
try {
|
|
1040
|
+
if (lifecycleModule().sweepStalePrNoOpFixes(pr)) updated = true;
|
|
1041
|
+
} catch (e) {
|
|
1042
|
+
log('warn', `sweepStalePrNoOpFixes for ${pr.id}: ${e.message}`);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1024
1045
|
return updated;
|
|
1025
1046
|
});
|
|
1026
1047
|
|
package/engine/lifecycle.js
CHANGED
|
@@ -2090,6 +2090,37 @@ function clearPrNoOpFixAttempt(target, cause) {
|
|
|
2090
2090
|
}
|
|
2091
2091
|
}
|
|
2092
2092
|
|
|
2093
|
+
// W-mpx44p05000ze8d8 — Proactive GC for stale `_noOpFixes` records. Called
|
|
2094
|
+
// from `engine/ado.js` + `engine/github.js` `pollPrStatus` after the live PR
|
|
2095
|
+
// fields (headSha, buildStatus, humanFeedback, mergeStatus, reviewStatus,
|
|
2096
|
+
// lastPushedAt, etc.) have been refreshed for the current tick. Any
|
|
2097
|
+
// `_noOpFixes[cause]` whose stored `evidenceFingerprint` no longer matches
|
|
2098
|
+
// the live one is dropped via `clearPrNoOpFixAttempt` — same cleanup the
|
|
2099
|
+
// resume endpoint and successful-fix path already use. Records without a
|
|
2100
|
+
// stored `evidenceFingerprint` (impossible from `recordPrNoOpFixAttempt`
|
|
2101
|
+
// today, but safe against future / legacy data) also drop, because the
|
|
2102
|
+
// dispatch gate already ignores them. Returns true when any record was
|
|
2103
|
+
// removed so the poll caller can flip its `updated` flag to persist the
|
|
2104
|
+
// purge.
|
|
2105
|
+
function sweepStalePrNoOpFixes(target) {
|
|
2106
|
+
if (!target || !target._noOpFixes || typeof target._noOpFixes !== 'object') return false;
|
|
2107
|
+
let modified = false;
|
|
2108
|
+
// Snapshot cause keys before mutation — clearPrNoOpFixAttempt deletes the
|
|
2109
|
+
// whole `_noOpFixes` object once the last record is removed, which would
|
|
2110
|
+
// invalidate a live `Object.keys()` iterator.
|
|
2111
|
+
const causes = Object.keys(target._noOpFixes);
|
|
2112
|
+
for (const cause of causes) {
|
|
2113
|
+
const record = target._noOpFixes[cause];
|
|
2114
|
+
if (!record || typeof record !== 'object') continue;
|
|
2115
|
+
const liveFp = shared.prFixEvidenceFingerprint(target, cause);
|
|
2116
|
+
if (record.evidenceFingerprint !== liveFp) {
|
|
2117
|
+
clearPrNoOpFixAttempt(target, cause);
|
|
2118
|
+
modified = true;
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
return modified;
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2093
2124
|
function updatePrAfterFix(pr, project, source, options = {}, legacyDispatchId = '') {
|
|
2094
2125
|
if (!pr?.id) return;
|
|
2095
2126
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
@@ -5137,6 +5168,10 @@ module.exports = {
|
|
|
5137
5168
|
// Issue #2969 — exported so dashboard.js can clear a paused cause from the
|
|
5138
5169
|
// resume endpoint.
|
|
5139
5170
|
clearPrNoOpFixAttempt,
|
|
5171
|
+
// W-mpx44p05000ze8d8 — exported so engine/ado.js + engine/github.js can
|
|
5172
|
+
// drop stale `_noOpFixes` records during their PR status poll, and so
|
|
5173
|
+
// unit tests can exercise the sweep helper directly.
|
|
5174
|
+
sweepStalePrNoOpFixes,
|
|
5140
5175
|
// Issue #2969 — exported for direct unit testing of the pause-flip alert
|
|
5141
5176
|
// path without going through updatePrAfterFix's many guards.
|
|
5142
5177
|
recordPrNoOpFixAttempt,
|
package/engine/shared.js
CHANGED
|
@@ -5261,20 +5261,18 @@ function isPrNoOpFixCausePaused(pr, cause) {
|
|
|
5261
5261
|
return record.evidenceFingerprint === prFixEvidenceFingerprint(pr, cause);
|
|
5262
5262
|
}
|
|
5263
5263
|
|
|
5264
|
-
// Issue #2969 — Derive the list of currently-paused
|
|
5265
|
-
// `/api/pull-requests` + the dashboard PR card.
|
|
5266
|
-
//
|
|
5267
|
-
//
|
|
5268
|
-
//
|
|
5269
|
-
//
|
|
5270
|
-
//
|
|
5264
|
+
// Issue #2969 / W-mpx44p05000ze8d8 — Derive the list of currently-paused
|
|
5265
|
+
// causes for surfacing on `/api/pull-requests` + the dashboard PR card.
|
|
5266
|
+
// Mirrors `isPrNoOpFixCausePaused` exactly: a cause is "paused" only when
|
|
5267
|
+
// `record.paused === true` AND the stored `evidenceFingerprint` still
|
|
5268
|
+
// matches the live PR's fingerprint. Without the fingerprint check the chip
|
|
5269
|
+
// surfaced stale pauses for PRs the dispatch gate had already cleared (the
|
|
5270
|
+
// engine would re-dispatch but the dashboard kept showing ⏸).
|
|
5271
5271
|
function getPrPausedCauses(pr) {
|
|
5272
5272
|
if (!pr || !pr._noOpFixes || typeof pr._noOpFixes !== 'object') return [];
|
|
5273
5273
|
const causes = [];
|
|
5274
|
-
for (const
|
|
5275
|
-
if (
|
|
5276
|
-
causes.push(cause);
|
|
5277
|
-
}
|
|
5274
|
+
for (const cause of Object.keys(pr._noOpFixes)) {
|
|
5275
|
+
if (isPrNoOpFixCausePaused(pr, cause)) causes.push(cause);
|
|
5278
5276
|
}
|
|
5279
5277
|
return causes;
|
|
5280
5278
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2102",
|
|
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"
|