@yemi33/minions 0.1.2367 → 0.1.2369

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/README.md CHANGED
@@ -7,6 +7,7 @@ A navigable index of every Markdown file under `docs/`. Entries are grouped by a
7
7
  Hands-on stories and distribution guides for people running or evaluating Minions.
8
8
 
9
9
  - [blog-first-successful-dispatch.md](blog-first-successful-dispatch.md) — Narrative walkthrough of the first end-to-end agent dispatch and the seven failed spawn attempts that preceded it.
10
+ - [architecture-review-2026-07-09.md](architecture-review-2026-07-09.md) — Architecture review covering engine orchestration, SQL/JSON state boundaries, runtime/process recovery, worktree lifecycle, pipelines/schedules, and prompt assembly, verified against `origin/main` at `b1b83dd2`.
10
11
  - [documentation-audit-2026-07-09.md](documentation-audit-2026-07-09.md) — Verified user-facing documentation audit covering runtime, CLI, storage, routing, and broken-link corrections.
11
12
  - [distribution.md](distribution.md) — How Minions is published (this repo: `@opg-microsoft/minions` to GitHub Packages; paired peer `@yemi33/minions` to npm) and the bidirectional sync contract — automated opg → yemi33 backport workflow + manual yemi33 → opg sync PRs.
12
13
  - [onboarding.md](onboarding.md) — Condensed first-30-minutes walkthrough for a new operator.
@@ -46,6 +47,7 @@ Architecture, design proposals, and lifecycle references for people working on t
46
47
  - [harness-transparency.md](harness-transparency.md) — The `harnessUsed` self-report contract: capture (agent reports the skills / MCPs / commands / docs it used) → ground (engine cross-checks against `_harnessPropagated` and annotates `grounded:true\|false`, never dropping) → surface (PR comment, final agent note, work-item modal).
47
48
  - [kb-dedup-duplicate-pair-investigation.md](kb-dedup-duplicate-pair-investigation.md) — Investigation-only pass diffing suspected duplicate KB filename groups (content-hash dedup for agent-authored reviews/build-reports) to confirm true full-body duplication before any fix is proposed.
48
49
  - [kb-pr3223-cascade-archiving.md](kb-pr3223-cascade-archiving.md) — Findings from PR #3223: cascade-archiving PRDs when their linked markdown plan is archived, including the per-concern try/catch pattern and `source_plan` basename-matching invariant in `handlePlansArchive` (`dashboard.js`).
50
+ - [kb-pr696-merge-conflict-docs.md](kb-pr696-merge-conflict-docs.md) — Findings from PR #696: resolving a merge conflict in `docs/kb-sweep.md` with stale line-number citations to `engine/kb-sweep.js`.
49
51
  - [kb-sweep.md](kb-sweep.md) — Knowledge-base consolidation sweep (hash dedup → LLM batch dedup/reclassify → per-entry compress) and the detached runner that keeps it alive across `minions restart`.
50
52
  - [keep-processes.md](keep-processes.md) — `meta.keep_processes` sidecar contract: when to use it vs managed-spawn, sidecar schema, caps, and the [`engine/keep-process-sweep.js`](../engine/keep-process-sweep.js) lifecycle.
51
53
  - [live-checkout-mode.md](live-checkout-mode.md) — Per-project opt-in `checkoutMode: 'live'`: skips `git worktree add` and dispatches in-place inside `project.localPath` for `repo`-managed trees, submodule-heavy repos, deep Windows paths, and native build state. Includes the refuse-on-dirty contract and the per-project mutating-concurrency cap of 1.
@@ -1,6 +1,6 @@
1
1
  # Auto-Discovery & Execution Pipeline
2
2
 
3
- > Last verified: 2026-06-09 against `engine.js` `tickInner()` and `routing.md`.
3
+ > Last verified: 2026-07-10 against `engine.js` `tickInner()` and `routing.md`.
4
4
 
5
5
  How the minions engine finds work and dispatches agents automatically.
6
6
 
@@ -28,16 +28,19 @@ tick()
28
28
  checkPlanCompletion() Mark plans completed when all features done/in-pr
29
29
  2.7 pollPrHumanComments() Poll PR threads for human comments (wall-clock cadence from prPollCommentsEvery × tickInterval, default ≈ 12min)
30
30
  reconcilePrs() (ADO+GH) Reconciliation sweep (runs regardless of poll flags)
31
+ reconcileSharedBranchPrs() Backfill the PR store for shared-branch plans whose aggregate remote PR is untracked/under-linked (runs unconditionally, like the other recovery sweeps)
31
32
  2.9 stallRecovery() Auto-retry failed items blocking pending deps (every 120 ticks)
32
33
  3a. pruneStalePrDispatches() Clear pending PR dispatches whose underlying PRs no longer warrant action
33
- 3. discoverWork() Scan ALL linked projects for new tasks
34
- 4. updateSnapshot() Write identity/now.md
35
- 4a. memoryBaseline() Sample RSS/heap/GC every memoryBaselineEveryTicks ticks (default 6 ≈ 60s)
36
- 4b. heapSnapshotRequest() Serve a pending guard-token heap-snapshot request, if any
37
- 5. dispatch Spawn agents for pending items (up to maxConcurrent)
34
+ 3. dispatch existing pending Spawn agents for items already durable in dispatch.pending (up to maxConcurrent) runs BEFORE discovery so a slow pre-dispatch validator can't starve already-queued work
35
+ 4. discoverWork() Scan ALL linked projects for new tasks
36
+ 5. updateSnapshot() Write identity/now.md
37
+ 5a. memoryBaseline() Sample RSS/heap/GC every memoryBaselineEveryTicks ticks (default 6 ≈ 60s)
38
+ 5b. heapSnapshotRequest() Serve a pending guard-token heap-snapshot request, if any
38
39
  ```
39
40
 
40
41
  > When `control.state === 'stopping'`, only steps 1–1c run; discovery and dispatch are skipped while live agents drain.
42
+ >
43
+ > Dispatch of already-pending work runs before `discoverWork()`, not after (`engine.js` comment: "Process pending dispatches before discovery. discoverWork() runs pre-dispatch LLM validation for newly found work; a slow validator must not starve runnable entries that are already durable in dispatch.pending.").
41
44
 
42
45
  ## Work Discovery
43
46
 
@@ -2593,6 +2593,18 @@ async function updatePrAfterReview(agentId, pr, project, config, resultSummary,
2593
2593
  }
2594
2594
  }
2595
2595
  target.lastReviewedAt = ts();
2596
+ // W-mrej8p740006b0bf — SHA-based review freshness. Persist the exact head
2597
+ // SHA the review verdict actually evaluated instead of leaning on
2598
+ // lastReviewedAt/lastPushedAt ordering, which flips "already reviewed"
2599
+ // true purely because the verdict was *recorded* after a mid-review push
2600
+ // landed — even though the verdict evaluated the prior head. Prefer the
2601
+ // SHA captured at dispatch time (meta.reviewHeadSha, stamped by
2602
+ // engine.js's review/re-review dispatch builders); fall back to the
2603
+ // current live head for older dispatches that predate that capture (best
2604
+ // effort — matches the previous timestamp-only behavior for those).
2605
+ const dispatchReviewedHeadSha = String(dispatchItem?.meta?.reviewHeadSha || '').trim();
2606
+ const liveHeadShaAtCompletion = getPrFixBaselineHead(target);
2607
+ target.reviewedHeadSha = dispatchReviewedHeadSha || liveHeadShaAtCompletion || target.reviewedHeadSha || '';
2596
2608
  // A verdict landed cleanly this time — clear any stale missing-verdict flag.
2597
2609
  delete target._reviewVerdictMissing;
2598
2610
  delete target._reviewVerdictMissingCount;
package/engine.js CHANGED
@@ -7378,6 +7378,42 @@ function getPrCauseBase(pr) {
7378
7378
  || '';
7379
7379
  }
7380
7380
 
7381
+ // W-mrej8p740006b0bf — SHA-based review freshness. A review is only
7382
+ // considered to cover the PR's CURRENT head when the recorded
7383
+ // `reviewedHeadSha` (the exact SHA the completed review verdict evaluated —
7384
+ // stamped by lifecycle.js#updatePrAfterReview from the dispatch's captured
7385
+ // `meta.reviewHeadSha`) matches the live head. This replaces the previous
7386
+ // `pr.lastPushedAt <= pr.lastReviewedAt` timestamp-ordering check, which
7387
+ // flips true purely because the verdict was *persisted* after a mid-review
7388
+ // push landed — even though the verdict evaluated the prior head (root cause
7389
+ // of github:opg-microsoft/minions#821: a commit pushed while a review was in
7390
+ // flight silently suppressed automatic re-review). Falls back to the legacy
7391
+ // timestamp comparison for PR records that predate `reviewedHeadSha`
7392
+ // capture, so existing open PRs don't all spuriously need re-review the
7393
+ // moment this ships.
7394
+ function isPrReviewCurrent(pr) {
7395
+ if (pr?.reviewedHeadSha) {
7396
+ const currentHead = getPrCauseHead(pr);
7397
+ return !!currentHead && pr.reviewedHeadSha === currentHead;
7398
+ }
7399
+ return !!(pr?.lastReviewedAt && (!pr?.lastPushedAt || pr.lastPushedAt <= pr.lastReviewedAt));
7400
+ }
7401
+
7402
+ // Same SHA-freshness signal applied to the WAITING → re-review gate. A fix
7403
+ // is "reviewed-stale" when the tracked `reviewedHeadSha` no longer matches
7404
+ // the live head — checked in addition to (not instead of) the existing
7405
+ // `fixedAt` vs `lastReviewedAt` timestamp comparison, so a mid-review push
7406
+ // during a re-review dispatch is caught the same way as the first-review
7407
+ // race above.
7408
+ function isPrFixedAfterReview(pr) {
7409
+ const timestampSaysFixed = !!(pr?.minionsReview?.fixedAt &&
7410
+ (!pr?.lastReviewedAt || pr.minionsReview.fixedAt > pr.lastReviewedAt));
7411
+ if (timestampSaysFixed) return true;
7412
+ if (!pr?.reviewedHeadSha) return false;
7413
+ const currentHead = getPrCauseHead(pr);
7414
+ return !!currentHead && pr.reviewedHeadSha !== currentHead;
7415
+ }
7416
+
7381
7417
  function getPrAutomationCauseKey(kind, pr) {
7382
7418
  if (kind === 'review-feedback') {
7383
7419
  const reviewRef = pr?.minionsReview?.dispatchId
@@ -7648,7 +7684,7 @@ async function discoverFromPrs(config, project) {
7648
7684
  // PRs needing review: evalLoop gates the entire review+fix cycle; pollEnabled ensures reviewStatus is fresh
7649
7685
  const reviewEnabled = evalLoopEnabled && pollEnabled && autoReviewPrs;
7650
7686
  const reReviewEnabled = evalLoopEnabled && pollEnabled && autoReReviewPrs;
7651
- const alreadyReviewed = pr.lastReviewedAt && (!pr.lastPushedAt || pr.lastPushedAt <= pr.lastReviewedAt);
7687
+ const alreadyReviewed = isPrReviewCurrent(pr);
7652
7688
  const needsReview = reviewEnabled && reviewStatus === REVIEW_STATUS.PENDING && !alreadyReviewed;
7653
7689
  if (needsReview) {
7654
7690
  const key = getPrReviewCooldownKey('review', project, pr, prDisplayId);
@@ -7694,7 +7730,7 @@ async function discoverFromPrs(config, project) {
7694
7730
  pr_author: pr.agent || '', pr_url: pr.url || '',
7695
7731
  }, `Review ${pr.id}: ${pr.title}`, {
7696
7732
  dispatchKey: key, source: 'pr', pr, branch: prBranch, project: projMeta,
7697
- deferReviewerResolution: true,
7733
+ deferReviewerResolution: true, reviewHeadSha: getPrCauseHead(pr),
7698
7734
  });
7699
7735
  if (deferred) {
7700
7736
  deferred._pendingReason = 'no_non_author_reviewer';
@@ -7707,7 +7743,7 @@ async function discoverFromPrs(config, project) {
7707
7743
  const item = buildPrDispatch(agentId, config, project, pr, 'review', {
7708
7744
  pr_id: pr.id, pr_number: prNumber, pr_title: pr.title || '', pr_branch: prBranch,
7709
7745
  pr_author: pr.agent || '', pr_url: pr.url || '',
7710
- }, `Review ${pr.id}: ${pr.title}`, { dispatchKey: key, cooldownKey: key, source: 'pr', pr, branch: prBranch, project: projMeta });
7746
+ }, `Review ${pr.id}: ${pr.title}`, { dispatchKey: key, cooldownKey: key, source: 'pr', pr, branch: prBranch, project: projMeta, reviewHeadSha: getPrCauseHead(pr) });
7711
7747
  if (item) { newWork.push(item); fixDispatched = true; }
7712
7748
  }
7713
7749
 
@@ -7861,8 +7897,7 @@ async function discoverFromPrs(config, project) {
7861
7897
 
7862
7898
  // Re-review after fix: trigger when a fix was pushed after the last minions review,
7863
7899
  // or when no minions review has completed yet (e.g. human-feedback-only fix path).
7864
- const fixedAfterReview = !!(pr.minionsReview?.fixedAt &&
7865
- (!pr.lastReviewedAt || pr.minionsReview.fixedAt > pr.lastReviewedAt));
7900
+ const fixedAfterReview = isPrFixedAfterReview(pr);
7866
7901
  const needsReReview = reReviewEnabled && reviewStatus === REVIEW_STATUS.WAITING &&
7867
7902
  fixedAfterReview && !fixDispatched;
7868
7903
  if (needsReReview) {
@@ -7909,7 +7944,7 @@ async function discoverFromPrs(config, project) {
7909
7944
  pr_author: pr.agent || '', pr_url: pr.url || '',
7910
7945
  }, `Review ${pr.id}: ${pr.title}`, {
7911
7946
  dispatchKey: key, cooldownKey: key, source: 'pr', pr, branch: prBranch, project: projMeta,
7912
- deferReviewerResolution: true,
7947
+ deferReviewerResolution: true, reviewHeadSha: getPrCauseHead(pr),
7913
7948
  });
7914
7949
  if (deferred) {
7915
7950
  deferred._pendingReason = 'no_non_author_reviewer';
@@ -7922,7 +7957,7 @@ async function discoverFromPrs(config, project) {
7922
7957
  const item = buildPrDispatch(agentId, config, project, pr, 'review', {
7923
7958
  pr_id: pr.id, pr_number: prNumber, pr_title: pr.title || '', pr_branch: prBranch,
7924
7959
  pr_author: pr.agent || '', pr_url: pr.url || '',
7925
- }, `Review ${pr.id}: ${pr.title}`, { dispatchKey: key, cooldownKey: key, source: 'pr', pr, branch: prBranch, project: projMeta });
7960
+ }, `Review ${pr.id}: ${pr.title}`, { dispatchKey: key, cooldownKey: key, source: 'pr', pr, branch: prBranch, project: projMeta, reviewHeadSha: getPrCauseHead(pr) });
7926
7961
  if (item) { newWork.push(item); }
7927
7962
  }
7928
7963
 
@@ -11716,6 +11751,7 @@ module.exports = {
11716
11751
  _isOutputTruncated, AGENT_OUTPUT_CAP_BYTES, // P-8e4c2a17: exported for testing (OUTPUT_TRUNCATED detection)
11717
11752
  promoteCheckpointSteeringForClose, // exported for testing
11718
11753
  normalizePrBranch, resolvePrBranch, prCausePart, getPrCauseHead, getPrCauseBase, getPrAutomationCauseKey, getPrAutomationDispatchKey, // exported for testing
11754
+ isPrReviewCurrent, isPrFixedAfterReview, // exported for testing (W-mrej8p740006b0bf — SHA-based review freshness)
11719
11755
  ensurePrBranchForDispatch, isWithinLinkGraceWindow, PR_LINK_GRACE_WINDOW_MS, // exported for testing (W-mphm0kt0000cebc3)
11720
11756
 
11721
11757
  // Playbooks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2367",
3
+ "version": "0.1.2369",
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"