@yemi33/minions 0.1.2424 → 0.1.2426

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 (185) hide show
  1. package/bin/install-internal-minions.js +1209 -0
  2. package/bin/minions.js +75 -9
  3. package/dashboard/docs/typography.md +27 -12
  4. package/dashboard/js/command-center.js +13 -11
  5. package/dashboard/js/live-stream.js +1 -1
  6. package/dashboard/js/memory-search.js +388 -43
  7. package/dashboard/js/modal-qa.js +5 -5
  8. package/dashboard/js/qa.js +39 -26
  9. package/dashboard/js/refresh.js +37 -18
  10. package/dashboard/js/render-agents.js +14 -18
  11. package/dashboard/js/render-dispatch.js +14 -74
  12. package/dashboard/js/render-inbox.js +3 -3
  13. package/dashboard/js/render-meetings.js +8 -8
  14. package/dashboard/js/render-other.js +45 -20
  15. package/dashboard/js/render-pipelines.js +6 -6
  16. package/dashboard/js/render-plans.js +14 -14
  17. package/dashboard/js/render-prd.js +46 -46
  18. package/dashboard/js/render-prs.js +9 -65
  19. package/dashboard/js/render-schedules.js +5 -5
  20. package/dashboard/js/render-skills.js +6 -6
  21. package/dashboard/js/render-utils.js +4 -4
  22. package/dashboard/js/render-watches.js +4 -16
  23. package/dashboard/js/render-work-items.js +95 -107
  24. package/dashboard/js/settings.js +175 -74
  25. package/dashboard/layout.html +3 -2
  26. package/dashboard/pages/inbox.html +1 -1
  27. package/dashboard/pages/work.html +1 -1
  28. package/dashboard/shared/model-display.js +9 -0
  29. package/dashboard/shared/watches-source.js +43 -0
  30. package/dashboard/shared/welcome-popup.js +259 -0
  31. package/dashboard/slim/body.html +6 -6
  32. package/dashboard/slim/js/chat.js +4 -2
  33. package/dashboard/slim/js/history.js +10 -3
  34. package/dashboard/slim/js/modals-tiles.js +85 -16
  35. package/dashboard/slim/js/status.js +12 -16
  36. package/dashboard/slim/styles.css +24 -4
  37. package/dashboard/styles.css +62 -27
  38. package/dashboard-build.js +8 -2
  39. package/dashboard.js +3854 -2514
  40. package/docs/README.md +7 -5
  41. package/docs/api-errors.md +144 -0
  42. package/docs/auto-discovery.md +83 -61
  43. package/docs/capture-demos.js +173 -30
  44. package/docs/command-center.md +5 -1
  45. package/docs/completion-reports.md +127 -11
  46. package/docs/constants.md +15 -3
  47. package/docs/constellation-style-telemetry.md +2 -2
  48. package/docs/copilot-cli-schema.md +32 -22
  49. package/docs/cross-repo-plans.md +30 -30
  50. package/docs/demo/memory-system.html +1 -1
  51. package/docs/deprecated.json +132 -18
  52. package/docs/diagnostics-memory.md +8 -4
  53. package/docs/human-vs-automated.md +2 -2
  54. package/docs/index.html +9 -2
  55. package/docs/internal-install.md +212 -0
  56. package/docs/kb-pr3223-cascade-archiving.md +16 -0
  57. package/docs/kb-pr696-merge-conflict-docs.md +23 -0
  58. package/docs/kb-sweep.md +2 -2
  59. package/docs/keep-processes.md +8 -1
  60. package/docs/live-checkout-mode.md +1 -1
  61. package/docs/managed-spawn.md +21 -3
  62. package/docs/named-agents.md +3 -2
  63. package/docs/onboarding.md +26 -0
  64. package/docs/plan-lifecycle.md +32 -32
  65. package/docs/pr-screenshots/pr-899/worker-pool-worktrees-AFTER.png +0 -0
  66. package/docs/pr-screenshots/pr-899/worker-pool-worktrees-BEFORE.png +0 -0
  67. package/docs/pr-screenshots/pr-979/auto-fix-pane-AFTER.png +0 -0
  68. package/docs/pr-screenshots/pr-979/auto-fix-pane-BEFORE.png +0 -0
  69. package/docs/pr-screenshots/pr-985/pr-column-em-dash-AFTER.png +0 -0
  70. package/docs/pr-screenshots/pr-985/pr-column-em-dash-BEFORE.png +0 -0
  71. package/docs/qa-runbook-lifecycle.md +67 -51
  72. package/docs/qa-runbooks.md +2 -2
  73. package/docs/runtime-adapters.md +101 -50
  74. package/docs/security.md +28 -0
  75. package/docs/self-improvement.md +47 -13
  76. package/docs/skills.md +29 -0
  77. package/docs/slim-ux/concepts.md +2 -2
  78. package/docs/specs/agent-configurability.md +43 -41
  79. package/docs/specs/agent-rename.md +13 -13
  80. package/docs/team-memory.md +283 -14
  81. package/docs/tutorials/01-install-and-connect.md +23 -0
  82. package/docs/tutorials/03-plan-driven-feature.md +3 -3
  83. package/docs/tutorials/04-runtimes-and-harness.md +18 -21
  84. package/docs/tutorials/08-operations-and-recovery.md +3 -2
  85. package/docs/tutorials/README.md +4 -3
  86. package/docs/visual-evidence-ci.md +103 -0
  87. package/docs/watches.md +35 -30
  88. package/docs/worktree-lifecycle.md +151 -13
  89. package/engine/acp-transport.js +1 -0
  90. package/engine/ado.js +80 -33
  91. package/engine/agent-api-validation.js +571 -0
  92. package/engine/agent-worker-pool.js +7 -6
  93. package/engine/api-contracts/agent-content.js +761 -0
  94. package/engine/api-contracts/cc-ops.js +219 -0
  95. package/engine/api-contracts/config-runtime.js +419 -0
  96. package/engine/api-contracts/core.js +138 -0
  97. package/engine/api-contracts/index.js +506 -0
  98. package/engine/api-contracts/orchestration.js +602 -0
  99. package/engine/api-contracts/pull-requests.js +323 -0
  100. package/engine/api-contracts/qa-process.js +764 -0
  101. package/engine/api-contracts/work-plan-prd.js +494 -0
  102. package/engine/api-validation.js +543 -0
  103. package/engine/cc-api-validation.js +586 -0
  104. package/engine/cc-worker-pool.js +9 -1
  105. package/engine/cleanup.js +393 -271
  106. package/engine/cli.js +65 -7
  107. package/engine/comment-classifier.js +70 -5
  108. package/engine/consolidation.js +123 -5
  109. package/engine/content-api-validation.js +606 -0
  110. package/engine/create-pr-worktree.js +22 -1
  111. package/engine/db/migrations/027-review-learning-lifecycle.js +162 -0
  112. package/engine/dispatch.js +33 -0
  113. package/engine/distribution.js +189 -0
  114. package/engine/execution-model.js +59 -0
  115. package/engine/features.js +12 -0
  116. package/engine/github.js +67 -25
  117. package/engine/harness-context.js +313 -0
  118. package/engine/inbox-store.js +1 -1
  119. package/engine/kb-sweep.js +161 -38
  120. package/engine/keep-process-sweep.js +43 -3
  121. package/engine/lifecycle.js +1066 -165
  122. package/engine/llm.js +4 -0
  123. package/engine/managed-spawn.js +463 -48
  124. package/engine/meeting.js +197 -34
  125. package/engine/memory-retrieval.js +280 -0
  126. package/engine/memory-store.js +821 -38
  127. package/engine/model-discovery.js +17 -3
  128. package/engine/pipeline.js +802 -14
  129. package/engine/plan-prd-validation.js +745 -0
  130. package/engine/playbook.js +206 -17
  131. package/engine/pooled-agent-process.js +6 -1
  132. package/engine/pr-action.js +1 -1
  133. package/engine/pr-issue-validation.js +653 -0
  134. package/engine/pr-resolve.js +75 -13
  135. package/engine/prd-store.js +39 -6
  136. package/engine/preflight.js +7 -2
  137. package/engine/process-utils.js +79 -31
  138. package/engine/projects.js +198 -12
  139. package/engine/promotion.js +371 -0
  140. package/engine/qa-from-prd.js +3 -0
  141. package/engine/qa-process-validation.js +572 -0
  142. package/engine/qa-runbooks.js +41 -37
  143. package/engine/qa-runners/maestro.js +11 -7
  144. package/engine/qa-runners/playwright.js +37 -14
  145. package/engine/qa-runners.js +9 -10
  146. package/engine/qa-runs.js +124 -11
  147. package/engine/qa-sessions.js +139 -40
  148. package/engine/quarantine-refs.js +81 -11
  149. package/engine/queries.js +163 -9
  150. package/engine/review-learning-backfill.js +482 -0
  151. package/engine/review-learning.js +1236 -0
  152. package/engine/runtimes/claude.js +60 -2
  153. package/engine/runtimes/codex.js +57 -16
  154. package/engine/runtimes/contract.js +21 -0
  155. package/engine/runtimes/copilot.js +51 -3
  156. package/engine/runtimes/index.js +1 -0
  157. package/engine/scheduler.js +201 -32
  158. package/engine/settings-validation.js +909 -0
  159. package/engine/shared.js +705 -208
  160. package/engine/spawn-agent.js +48 -21
  161. package/engine/steering-constraints.js +31 -0
  162. package/engine/steering-store.js +10 -2
  163. package/engine/steering.js +14 -2
  164. package/engine/timeout.js +404 -111
  165. package/engine/untrusted-fence.js +24 -10
  166. package/engine/watch-actions.js +7 -2
  167. package/engine/watches.js +353 -51
  168. package/engine/work-item-validation.js +561 -0
  169. package/engine/work-items-store.js +61 -1
  170. package/engine/worktree-gc.js +656 -37
  171. package/engine/worktree-preflight.js +154 -0
  172. package/engine.js +2068 -342
  173. package/package.json +1 -1
  174. package/playbooks/_pr-description-audit.md +88 -41
  175. package/playbooks/build-fix-complex.md +3 -3
  176. package/playbooks/docs.md +2 -2
  177. package/playbooks/fix.md +18 -18
  178. package/playbooks/implement.md +18 -18
  179. package/playbooks/qa-session-draft.md +10 -12
  180. package/playbooks/qa-session-execute.md +16 -12
  181. package/playbooks/qa-validate.md +8 -7
  182. package/playbooks/shared-rules.md +45 -0
  183. package/playbooks/test.md +4 -0
  184. package/prompts/cc-system.md +1 -1
  185. package/skills/check-self-authored-review-comment/SKILL.md +2 -2
@@ -29,30 +29,43 @@ function getRepoHost(project) {
29
29
  return project?.repoHost || 'ado';
30
30
  }
31
31
 
32
- function getPrCreateInstructions(project) {
32
+ function getPrCreateInstructions(project, config) {
33
33
  const host = getRepoHost(project);
34
34
  const repoId = project?.repositoryId || '';
35
+ // W-mrtdy7xv — createPrsAsDraft: when ON, tell agents to open the PR
36
+ // as a draft (host-aware). Per-project-overridable (W-mrxv648b): a project
37
+ // can opt IN or OUT of draft PRs independent of the fleet-wide engine flag.
38
+ // Resolved via shared.resolveCreatePrsAsDraft(project, engine): explicit
39
+ // per-project boolean wins → else engine flag → else ENGINE_DEFAULTS (false).
40
+ const createPrsAsDraft = shared.resolveCreatePrsAsDraft(project, config?.engine);
35
41
  if (host === 'github') {
36
42
  const org = getProjectOrg(project);
37
43
  const repo = project?.repoName || '';
38
44
  const mainBranch = project?.localPath ? shared.resolveMainBranch(project.localPath, project.mainBranch) : (project?.mainBranch || 'main');
45
+ const draftFlag = createPrsAsDraft ? ' --draft' : '';
39
46
  return `Use \`gh pr create\` to create a pull request:\n` +
40
- `- Write the PR description to a temporary Markdown file, then run: \`gh pr create --base ${mainBranch} --head <your-branch> --title "PR title" --body-file <body-file.md> --repo ${org}/${repo}\`\n` +
47
+ `- Write the PR description to a temporary Markdown file, then run: \`gh pr create --base ${mainBranch} --head <your-branch> --title "PR title" --body-file <body-file.md> --repo ${org}/${repo}${draftFlag}\`\n` +
41
48
  `- Always set --base to \`${mainBranch}\` (the main branch)\n` +
42
49
  `- Always set --repo to \`${org}/${repo}\` to target the correct repository\n` +
43
50
  `- Use --head to specify your feature branch name\n` +
44
- `- Include a meaningful --title and body file describing the changes`;
51
+ (createPrsAsDraft ? `- Open the PR as a DRAFT: include the \`--draft\` flag exactly as shown above (the operator has "Create PRs as draft" enabled)\n` : '') +
52
+ `- Include a meaningful --title and body file describing the changes\n` +
53
+ `- If this PR contains a meaningful VISUAL/UI change (dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS), proactively capture + EMBED screenshots in the body — BEFORE/AFTER for fixes, AFTER-only for new UI. Publish PNGs as assets on a per-PR prerelease (\`gh release create pr-<num>-visual … --prerelease\`, or \`gh release upload … --clobber\` on re-dispatch) with a per-command \`GH_TOKEN\` for the ${org} account (NEVER \`gh auth switch\`), resolve each \`browser_download_url\`, and reference it as \`![view (after)](url)\`. Never \`git add\` a PNG; skip + record on failure. Full recipe: the "Screenshot handling" section of the PR description audit.`;
45
54
  }
46
55
  // Default: Azure DevOps — prefer `az` CLI first, ADO REST API as fallback
47
56
  const adoOrg = project?.adoOrg || '';
48
57
  const adoProject = project?.adoProject || '';
49
58
  const repoName = project?.repoName || '';
50
59
  const mainBranch = project?.localPath ? shared.resolveMainBranch(project.localPath, project.mainBranch) : (project?.mainBranch || 'main');
60
+ const adoDraftFlag = createPrsAsDraft ? ' --draft true' : '';
51
61
  return `For Azure DevOps, use the \`az\` CLI first to create a pull request:\n` +
52
62
  `- Run \`az devops configure --defaults organization=https://dev.azure.com/${adoOrg} project="${adoProject}"\` once per session if defaults are not yet set\n` +
53
- `- Then: \`az repos pr create --repository "${repoName}" --source-branch <your-branch> --target-branch ${mainBranch} --title "PR title" --description @<body-file.md>\`\n` +
63
+ `- Then: \`az repos pr create --repository "${repoName}" --source-branch <your-branch> --target-branch ${mainBranch} --title "PR title" --description @<body-file.md>${adoDraftFlag}\`\n` +
54
64
  `- Use \`@<file>\` syntax for \`--description\` so Markdown, quotes, and newlines pass safely\n` +
55
- `- Always set --target-branch to \`${mainBranch}\` (the main branch)\n\n` +
65
+ `- Always set --target-branch to \`${mainBranch}\` (the main branch)\n` +
66
+ (createPrsAsDraft ? `- Open the PR as a DRAFT: include \`--draft true\` exactly as shown above (the operator has "Create PRs as draft" enabled). For the REST API fallback, set \`"isDraft": true\` in the request body\n` : '') +
67
+ `- If this PR contains a meaningful VISUAL/UI change (dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS), proactively capture + EMBED screenshots in the description — BEFORE/AFTER for fixes, AFTER-only for new UI. Upload via \`PUT .../pullRequests/<id>/attachments/<filename>\` with the PNG bytes and reference the returned URL. Save PNGs under \`agents/<id>/screenshots/\` only; never \`git add\` a PNG; skip + record on failure. Full recipe: the "Screenshot handling" section of the PR description audit\n` +
68
+ `\n` +
56
69
  `If \`az\` is unavailable, fall back to the ADO REST API: get a token with \`az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv\` and \`POST .../_apis/git/repositories/${repoId}/pullrequests?api-version=7.1\` (Bearer auth). Do not use \`gh\` for Azure DevOps repositories.`;
57
70
  }
58
71
 
@@ -415,7 +428,7 @@ const PLAYBOOK_REQUIRED_VARS = {
415
428
  'test': ['item_name'],
416
429
  'docs': ['item_id', 'item_name'],
417
430
  'setup': ['item_id', 'item_name', 'project_path'],
418
- 'qa-validate': ['item_id', 'item_name', 'qa_run_id'],
431
+ 'qa-validate': ['item_id', 'item_name', 'qa_run_id', 'qa_artifacts_dir', 'qa_result_sidecar'],
419
432
  // P-e6b3c2d8 — QA Session SETUP phase. Required vars are session
420
433
  // identification + target kind + flows + the deterministic managed-spawn
421
434
  // name the engine joins back to the session on. Conditional target_*
@@ -426,11 +439,11 @@ const PLAYBOOK_REQUIRED_VARS = {
426
439
  // flows + the live managed-spawn name + the runner adapter's
427
440
  // generateBrief() output. The brief is computed at render time by
428
441
  // engine.js (lazy-required qa-sessions + qa-runners + managed-spawn).
429
- 'qa-session-draft': ['session_id', 'flows_raw', 'managed_spawn_name', 'runner_brief'],
442
+ 'qa-session-draft': ['session_id', 'flows_raw', 'managed_spawn_name', 'managed_spawn_lookup_url', 'qa_test_dir', 'runner_brief'],
430
443
  // P-f9a2e1b4 — QA Session EXECUTE phase. Required vars are session id +
431
444
  // live managed-spawn name + executeBrief() output + the qa-runs record id
432
445
  // (the agent stamps it on the result sidecar so lifecycle.js can ingest it).
433
- 'qa-session-execute': ['session_id', 'managed_spawn_name', 'runner_execute_brief', 'qa_run_id'],
446
+ 'qa-session-execute': ['session_id', 'managed_spawn_name', 'managed_spawn_lookup_url', 'runner_execute_brief', 'qa_run_id', 'qa_artifacts_dir', 'qa_result_sidecar'],
434
447
  'work-item': ['item_id', 'item_name'],
435
448
  'meeting-investigate': ['meeting_title', 'agenda'],
436
449
  'meeting-debate': ['meeting_title', 'agenda'],
@@ -443,6 +456,31 @@ const LIVE_VALIDATION_DEFERRED_PLAYBOOKS = new Set([
443
456
  'build-fix-complex',
444
457
  ]);
445
458
 
459
+ // W-mrtdmtwq000kf391 — playbooks whose completion can open or update a
460
+ // Minions-authored PR body. Only these dispatches get the "Repo harnesses used"
461
+ // PR-body appendix, AND only when the work item's resolved PR contract actually
462
+ // produces/updates a PR (see the `skip_pr` / `shared_branch` gates at the
463
+ // injection site). Review/explore/ask/plan/meeting dispatches post comments or
464
+ // produce artifacts rather than authoring a PR body, so they are excluded.
465
+ //
466
+ // This set is aligned with the real per-playbook PR contract, NOT a loose
467
+ // name allowlist (reviewer BLOCKING, PR #898):
468
+ // - `setup` (playbooks/setup.md) explicitly produces NO PR — excluded.
469
+ // - `build-and-test` (playbooks/build-and-test.md) is read-only ("Do not
470
+ // create pull requests or push commits") — excluded.
471
+ // - `test` (playbooks/test.md) CAN create a PR when it changes files — included
472
+ // (the fenced block is a no-op when the dispatch opens no PR, since the agent
473
+ // only appends it to a PR body it actually authors).
474
+ const PR_AUTHORING_PLAYBOOKS = new Set([
475
+ 'implement',
476
+ 'work-item',
477
+ 'fix',
478
+ 'build-fix-complex',
479
+ 'verify',
480
+ 'docs',
481
+ 'test',
482
+ ]);
483
+
446
484
  /**
447
485
  * Validate that all required template variables for a playbook type are present
448
486
  * and non-empty in the provided vars object.
@@ -530,13 +568,14 @@ function resolvePlaybookPath(projectName, playbookType) {
530
568
  // and renders a compact, prompt-friendly summary. Heavy guards against
531
569
  // missing fields because dispatch callers may supply partial snapshots when
532
570
  // the managed-process state has rotated between schedule and dispatch.
533
- function buildQaValidateContextBlock({ runId, runbook, target, artifactsDir }) {
571
+ function buildQaValidateContextBlock({ runId, runbook, target, artifactsDir, resultSidecar }) {
534
572
  if (!runId) return '';
535
573
  const lines = [];
536
574
  lines.push('## QA Run Context');
537
575
  lines.push('');
538
576
  lines.push(`- **runId:** \`${runId}\``);
539
577
  if (artifactsDir) lines.push(`- **artifactsDir:** \`${artifactsDir}\``);
578
+ if (resultSidecar) lines.push(`- **resultSidecar:** \`${resultSidecar}\``);
540
579
  lines.push('');
541
580
 
542
581
  const rb = runbook && typeof runbook === 'object' ? runbook : null;
@@ -582,7 +621,7 @@ function buildQaValidateContextBlock({ runId, runbook, target, artifactsDir }) {
582
621
  lines.push('');
583
622
  }
584
623
 
585
- lines.push('Use this context to execute the runbook against the live target. Write the result sidecar to `agents/<your-id>/qa-run-result.json` before exit — the engine consumes it in `engine/lifecycle.js` and calls `qaRuns.completeRun(runId, ...)`.');
624
+ lines.push(`Use this context to execute the runbook against the live target. Write the result sidecar to \`${resultSidecar || 'the injected qa_result_sidecar path'}\` before exit — the engine consumes it in \`engine/lifecycle.js\` and calls \`qaRuns.completeRun(runId, ...)\`.`);
586
625
 
587
626
  return lines.join('\n');
588
627
  }
@@ -744,6 +783,80 @@ function renderPlaybook(type, vars) {
744
783
  }
745
784
  }
746
785
 
786
+ // Reserved deterministic review-lesson recall (P-a6137579). A dedicated
787
+ // project + audience path, independent of the generic memory budget above and
788
+ // gated on its own feature flag. Review-learning records are globally excluded
789
+ // from generic recall, so with recall off (capture-only) the rendered prompt
790
+ // is unchanged with respect to those records. Only dispatches with a resolved
791
+ // project context are eligible; projectless CC / central work get no section.
792
+ if (projectName && features.isFeatureOn('review-learning-recall', configEarly)) {
793
+ try {
794
+ const applicable = memoryRetrieval.retrieveApplicableReviewLearnings({
795
+ title: vars.item_name || vars.pr_title || '',
796
+ description: vars.item_description || vars.task_description || vars.pr_description || '',
797
+ type: vars.work_type || type,
798
+ project: projectName,
799
+ agent: vars.agent_id || '',
800
+ failureClass: vars.failure_class || '',
801
+ sourcePlan: vars.source_plan || '',
802
+ references: vars.references || '',
803
+ prTitle: vars.pr_title || '',
804
+ prBranch: vars.pr_branch || '',
805
+ });
806
+ memoryStore.recordRetrievalRun({
807
+ workItemId: vars.item_id || null,
808
+ dispatchId: vars.task_id || null,
809
+ project: projectName,
810
+ agent: vars.agent_id || null,
811
+ retrievalKind: 'review-learning',
812
+ query: [...applicable.hints.files, ...applicable.hints.symbols, ...applicable.hints.tags].join(' '),
813
+ candidateCount: applicable.candidates.length,
814
+ selectedCount: applicable.selected.length,
815
+ selectedBytes: applicable.bytes,
816
+ durationMs: applicable.durationMs,
817
+ selectedIds: applicable.selectedIds,
818
+ decisionTrace: applicable.decisionTrace,
819
+ });
820
+ // P-bfc75585 — per-lesson `retrieved` lifecycle events. The retrieval run
821
+ // above records the aggregate selection; these events give the per-lesson
822
+ // audit trail that the completion's reviewLearningApplications are matched
823
+ // against. Deterministic event keys (dispatchId + memoryId) keep re-renders
824
+ // idempotent. Best-effort: an audit write must never break prompt render.
825
+ for (const record of applicable.selected || []) {
826
+ if (!record || !record.id) continue;
827
+ try {
828
+ memoryStore.recordMemoryLifecycleEvent({
829
+ eventType: 'retrieved',
830
+ memoryId: record.id,
831
+ findingKey: record.sourceRef || null,
832
+ project: projectName,
833
+ agent: vars.agent_id || null,
834
+ area: record.metadata?.area || 'general',
835
+ disposition: record.metadata?.disposition || null,
836
+ workItemId: vars.item_id || null,
837
+ dispatchId: vars.task_id || null,
838
+ identity: record.id,
839
+ metadata: {
840
+ audience: record.metadata?.audience || 'project-team',
841
+ retrievalKind: 'review-learning',
842
+ },
843
+ });
844
+ } catch (eventErr) {
845
+ log('warn', `Review-learning retrieved-event failed for ${record.id}: ${eventErr.message}`);
846
+ }
847
+ }
848
+ if (applicable.text) {
849
+ const fenced = wrapUntrusted(
850
+ applicable.text,
851
+ buildSource('review-learning', { item: vars.item_id || vars.task_id || 'unknown' })
852
+ );
853
+ inertAppendices.push('\n\n---\n\n## Applicable Prior Review Lessons (task-selected; verify against live code)\n\n' + (fenced || applicable.text));
854
+ }
855
+ } catch (e) {
856
+ log('warn', `Review-learning recall failed for ${vars.item_id || vars.task_id || type}: ${e.message}`);
857
+ }
858
+ }
859
+
747
860
  // Inject team notes (single injection point — not in buildAgentContext) — capped via ENGINE_DEFAULTS.
748
861
  // F5: wrap in <UNTRUSTED-INPUT> fence — notes.md is an LLM-consolidated mix
749
862
  // of agent inbox notes (semi-trusted) and human edits.
@@ -792,19 +905,33 @@ function renderPlaybook(type, vars) {
792
905
  // there is nothing to conflict with). Bounded discovery (nearest-applicable
793
906
  // walk-up, byte-capped) lives in engine/claude-md-context.js. Degrades
794
907
  // silently on any error.
908
+ //
909
+ // These resolved facts (runtime, bare mode, propagation flag, and the ACTUAL
910
+ // injected file list) are hoisted so the "Repo harnesses used" PR-body section
911
+ // below reports the same resolved reality the engine actually injected, rather
912
+ // than re-discovering statically (reviewer BLOCKING, PR #898).
913
+ const harnessAgentCfg = configEarly?.agents?.[vars.agent_id] || null;
914
+ const harnessCliName = vars.runtime_cli || shared.resolveAgentCli(harnessAgentCfg, configEarly?.engine);
915
+ const harnessBareMode = shared.resolveAgentBareMode(harnessAgentCfg, configEarly?.engine);
916
+ let harnessClaudeMdCtx = null;
917
+ try { harnessClaudeMdCtx = require('./claude-md-context'); } catch { /* optional */ }
918
+ const runtimeNativeClaudeMd = harnessClaudeMdCtx
919
+ ? !!harnessClaudeMdCtx.runtimeAutoDiscoversClaudeMd(harnessCliName) : false;
920
+ const propagateClaudeMd = shared.resolvePropagateClaudeMdForNonClaudeRuntimes(matchedProject, configEarly?.engine);
921
+ let claudeMdInjectedFiles = [];
795
922
  try {
796
- const claudeMdCtx = require('./claude-md-context');
797
- const cliName = vars.runtime_cli || shared.resolveAgentCli(null, configEarly?.engine);
798
923
  const projectRoot = matchedProject?.localPath;
799
924
  if (projectRoot
800
- && !claudeMdCtx.runtimeAutoDiscoversClaudeMd(cliName)
801
- && shared.resolvePropagateClaudeMdForNonClaudeRuntimes(matchedProject, configEarly?.engine)) {
925
+ && harnessClaudeMdCtx
926
+ && !runtimeNativeClaudeMd
927
+ && propagateClaudeMd) {
802
928
  const pathHints = Array.isArray(vars.claude_md_path_hints) ? vars.claude_md_path_hints : [];
803
- const { block } = claudeMdCtx.buildClaudeMdPropagationBlock({
929
+ const { block, files } = harnessClaudeMdCtx.buildClaudeMdPropagationBlock({
804
930
  projectRoot,
805
931
  pathHints,
806
932
  maxBytes: ENGINE_DEFAULTS.maxNotesPromptBytes,
807
933
  });
934
+ claudeMdInjectedFiles = Array.isArray(files) ? files : [];
808
935
  if (block) {
809
936
  const fenced = wrapUntrusted(block, buildSource('project-instructions', { path: 'CLAUDE.md' }));
810
937
  inertAppendices.push(
@@ -819,6 +946,67 @@ function renderPlaybook(type, vars) {
819
946
  }
820
947
  } catch (e) { log('warn', `CLAUDE.md propagation inject failed: ${e.message}`); }
821
948
 
949
+ // W-mrtdmtwq000kf391 — surface the repo HARNESS assets in effect for this
950
+ // dispatch (runtime + project) in the Minions-authored PR body. We compute a
951
+ // compact, deterministic inventory from the read-only harness-diagnostics
952
+ // source and instruct the agent to append it (verbatim, fenced) to its PR
953
+ // description. Gated on: the flag (default on), a resolved project, a
954
+ // PR-authoring playbook, and the work item's resolved PR contract — NOT a
955
+ // shared-branch item (those never self-PR) and NOT a `skipPr` item (QA-session
956
+ // SETUP/DRAFT/EXECUTE and any PR-less work). Reporting only — no
957
+ // propagation/attestation (docs/harness-propagation.md).
958
+ //
959
+ // The inventory is derived from the RESOLVED dispatch: the same runtime, bare
960
+ // mode, propagation flag, injected CLAUDE.md files, and dispatch worktree the
961
+ // engine actually used — so the section never over-claims context the runtime
962
+ // never saw (reviewer BLOCKING, PR #898).
963
+ if (matchedProject
964
+ && !vars.shared_branch
965
+ && !vars.skip_pr
966
+ && PR_AUTHORING_PLAYBOOKS.has(type)
967
+ && (configEarly?.engine?.includeHarnessSectionInPrBody !== false)) {
968
+ try {
969
+ const harnessCtx = require('./harness-context');
970
+ const { inventory, section } = harnessCtx.renderHarnessSectionForDispatch({
971
+ runtimeCli: harnessCliName,
972
+ project: matchedProject,
973
+ worktreePath: vars.worktree_path || '',
974
+ bareMode: harnessBareMode,
975
+ nativeClaudeMd: runtimeNativeClaudeMd,
976
+ claudeMdInjectedFiles,
977
+ propagateClaudeMd,
978
+ pathHints: Array.isArray(vars.claude_md_path_hints) ? vars.claude_md_path_hints : [],
979
+ });
980
+ if (section) {
981
+ // Skills are the one category the engine can't resolve ahead of time —
982
+ // it knows which project skills are AVAILABLE but not which the agent
983
+ // will actually invoke. Hand the available list to the agent as a
984
+ // reference (prompt only, never the PR body) and have it report the
985
+ // subset it actually used. This keeps the block "used, not discovered".
986
+ const availableSkills = Array.isArray(inventory?.availableSkills) ? inventory.availableSkills : [];
987
+ const skillsGuidance = availableSkills.length
988
+ ? 'If — and only if — you actually invoked one or more repo skills while doing this '
989
+ + 'work, add a single `- **Skills used:** <comma-separated names>` line inside the '
990
+ + 'block (before the end marker), listing ONLY the skills you actually used. Omit '
991
+ + 'the line entirely if you used none. Do NOT list skills you did not use. The '
992
+ + 'project skills available to you this dispatch were: '
993
+ + availableSkills.join(', ') + '.\n\n'
994
+ : '';
995
+ inertAppendices.push(
996
+ '\n\n---\n\n## Repo harnesses — include in your PR body\n\n'
997
+ + 'When you open or update the PR for this dispatch, append the block below to the PR '
998
+ + 'description (keep the `' + harnessCtx.HARNESS_BLOCK_START + '` / `'
999
+ + harnessCtx.HARNESS_BLOCK_END + '` markers). If the PR body already contains a block '
1000
+ + 'between those markers, replace it in place instead of adding a second copy. The '
1001
+ + 'engine-resolved lines (runtime, CLAUDE.md, AGENTS.md, MCP) report what was actually '
1002
+ + 'in effect for this runtime + project — keep them as given.\n\n'
1003
+ + skillsGuidance
1004
+ + section,
1005
+ );
1006
+ }
1007
+ } catch (e) { log('warn', `harness PR-section inject failed: ${e.message}`); }
1008
+ }
1009
+
822
1010
  // W-mp68q6ke0010de68 — opt-in keep_processes hint. Injected only when the
823
1011
  // dispatcher set vars.keep_processes (truthy) from the work item's
824
1012
  // `meta.keep_processes`. Built via the keep-process-sweep module so the
@@ -882,6 +1070,7 @@ function renderPlaybook(type, vars) {
882
1070
  runbook: vars.qa_runbook,
883
1071
  target: vars.qa_target,
884
1072
  artifactsDir: vars.qa_artifacts_dir,
1073
+ resultSidecar: vars.qa_result_sidecar,
885
1074
  });
886
1075
  if (block) inertAppendices.push(block);
887
1076
  } catch (e) { log('warn', `qa-validate context render failed: ${e.message}`); }
@@ -962,7 +1151,7 @@ function renderPlaybook(type, vars) {
962
1151
  repo_host: repoHost,
963
1152
  ado_shared_rules: repoHost === 'ado' ? '1' : '',
964
1153
  github_shared_rules: repoHost === 'github' ? '1' : '',
965
- pr_create_instructions: getPrCreateInstructions(renderProject),
1154
+ pr_create_instructions: getPrCreateInstructions(renderProject, config),
966
1155
  pr_comment_instructions: getPrCommentInstructions(renderProject),
967
1156
  pr_fetch_instructions: getPrFetchInstructions(renderProject),
968
1157
  pr_vote_instructions: getPrVoteInstructions(renderProject, config),
@@ -1139,7 +1328,7 @@ function buildAgentContext(agentId, config, project) {
1139
1328
  if (history && history.trim() !== '# Agent History') {
1140
1329
  const entries = history.split(/(?=^### )/m);
1141
1330
  const header = entries[0].startsWith('#') && !entries[0].startsWith('### ') ? entries.shift() : '';
1142
- const recent = entries.slice(-5);
1331
+ const recent = entries.slice(0, 5);
1143
1332
  const trimmed = (header ? header + '\n' : '') + recent.join('');
1144
1333
  context += `## Your Recent History (last 5 tasks)\n\n${trimmed}\n\n`;
1145
1334
  }
@@ -16,8 +16,13 @@
16
16
  * ACP lease.
17
17
  *
18
18
  * Output translation (parity, not full fidelity) is adapter-owned through
19
- * `encodePooledOutput()`. The facade only forwards semantic chunk/result
19
+ * `encodePooledOutput()`. The facade only forwards semantic model/chunk/result
20
20
  * events, so a harness can change its JSONL schema without changing this file.
21
+ *
22
+ * Before returning a healthy worker, the facade snapshots and reaps process
23
+ * trees created by this lease while preserving baseline worker/MCP descendants
24
+ * and validated keep_processes anchors. Cleanup uncertainty discards the worker
25
+ * instead of exposing its leftover processes to the next dispatch.
21
26
  */
22
27
 
23
28
  const { EventEmitter } = require('events');
@@ -278,7 +278,7 @@ function resolvePrActionRequest({ url, action } = {}) {
278
278
  if (!rawUrl) throw new PrActionError('url required');
279
279
 
280
280
  const ref = prResolve.normalizePrRef(rawUrl);
281
- if (!ref) throw new PrActionError(`unrecognized PR reference: ${JSON.stringify(rawUrl.slice(0, 120))}`);
281
+ if (!ref) throw new PrActionError('unrecognized PR reference');
282
282
 
283
283
  return { action: act, ref };
284
284
  }