nexus-agents 2.134.0 → 2.136.0

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 (153) hide show
  1. package/dist/{child-mcp-config-TWHH63UK.js → child-mcp-config-TM6OCARU.js} +4 -3
  2. package/dist/{child-mcp-config-TWHH63UK.js.map → child-mcp-config-TM6OCARU.js.map} +1 -1
  3. package/dist/{chunk-E64SZTEP.js → chunk-257QMFTM.js} +3 -3
  4. package/dist/{chunk-PQHVC4BD.js → chunk-2XRPKJKX.js} +23 -12
  5. package/dist/chunk-2XRPKJKX.js.map +1 -0
  6. package/dist/{chunk-FUJ3XR7T.js → chunk-3AAJWZCR.js} +4 -4
  7. package/dist/{chunk-Z6DXZ6AS.js → chunk-3JSDOBOA.js} +2 -2
  8. package/dist/{chunk-FPMQ2JAK.js → chunk-3QH2KWLH.js} +2 -2
  9. package/dist/{chunk-7TQZR5VU.js → chunk-3WBEEYCS.js} +116 -22
  10. package/dist/chunk-3WBEEYCS.js.map +1 -0
  11. package/dist/{chunk-UDB5NHJI.js → chunk-4GVPON4W.js} +3 -3
  12. package/dist/{chunk-QZUT22LP.js → chunk-5546JU53.js} +8 -8
  13. package/dist/chunk-5SXGPX34.js +44 -0
  14. package/dist/chunk-5SXGPX34.js.map +1 -0
  15. package/dist/{chunk-7GSYICTL.js → chunk-66TXNH4S.js} +14 -12
  16. package/dist/{chunk-7GSYICTL.js.map → chunk-66TXNH4S.js.map} +1 -1
  17. package/dist/{chunk-76R5ES6Z.js → chunk-6JOXXQK2.js} +191 -132
  18. package/dist/chunk-6JOXXQK2.js.map +1 -0
  19. package/dist/{chunk-ZMDOGN33.js → chunk-7E5UXA4U.js} +2 -2
  20. package/dist/{chunk-F74ZGHAP.js → chunk-7G63H7ZT.js} +2 -2
  21. package/dist/{chunk-FVSZLVMR.js → chunk-CQDGPGTL.js} +3 -3
  22. package/dist/{chunk-33MFMXBQ.js → chunk-ESP6U3LW.js} +13 -81
  23. package/dist/chunk-ESP6U3LW.js.map +1 -0
  24. package/dist/{chunk-MY52DFXC.js → chunk-FHFEC2XM.js} +2 -2
  25. package/dist/{chunk-ORQAFTAZ.js → chunk-FIQSOSQU.js} +2 -2
  26. package/dist/{chunk-EHLJLIHS.js → chunk-FSUZIIOJ.js} +2 -2
  27. package/dist/{chunk-3EYXPV5F.js → chunk-GWOXPCIF.js} +13 -13
  28. package/dist/{chunk-WYJJUF6N.js → chunk-HMZT2SJK.js} +4 -4
  29. package/dist/{chunk-OCKZ6F5O.js → chunk-JK4L2TQ6.js} +3 -3
  30. package/dist/{chunk-6UCWR3DS.js → chunk-JVZ7FGWR.js} +3 -3
  31. package/dist/{chunk-PFBV5FCT.js → chunk-KOVTOPEQ.js} +2 -2
  32. package/dist/{chunk-GZ4NF4ZW.js → chunk-L4QFWOOQ.js} +63 -92
  33. package/dist/chunk-L4QFWOOQ.js.map +1 -0
  34. package/dist/{chunk-6LMZ7HFU.js → chunk-LCSGGLZZ.js} +2 -2
  35. package/dist/{chunk-IWQH6TP7.js → chunk-MTE7THMR.js} +6 -6
  36. package/dist/{chunk-DLUFDKPA.js → chunk-N67LHY47.js} +89 -32
  37. package/dist/chunk-N67LHY47.js.map +1 -0
  38. package/dist/{chunk-DBDWMHUL.js → chunk-OCJEYHUQ.js} +18 -10
  39. package/dist/chunk-OCJEYHUQ.js.map +1 -0
  40. package/dist/chunk-UGAKYSDO.js +92 -0
  41. package/dist/chunk-UGAKYSDO.js.map +1 -0
  42. package/dist/{chunk-VI7LELES.js → chunk-UH3F4RZB.js} +7 -7
  43. package/dist/{chunk-COJOUIO2.js → chunk-VN3CKPEF.js} +3 -3
  44. package/dist/{chunk-FSFF7EFR.js → chunk-VVBKPRLI.js} +2 -2
  45. package/dist/{chunk-OU2NQVKD.js → chunk-VY4FZNZA.js} +2 -2
  46. package/dist/{chunk-BTYYZ6VU.js → chunk-WOE5J5M6.js} +4 -4
  47. package/dist/{chunk-B26FGLIJ.js → chunk-ZHCEOIEQ.js} +2 -2
  48. package/dist/{chunk-WFKVUZ3O.js → chunk-ZII5MDUO.js} +2 -2
  49. package/dist/{chunk-CLRSNWRQ.js → chunk-ZLENFXL5.js} +4 -4
  50. package/dist/cli-circuit-breaker-HFFMCA43.js +14 -0
  51. package/dist/cli.d.ts +1 -1
  52. package/dist/cli.js +68 -66
  53. package/dist/cli.js.map +1 -1
  54. package/dist/{composite-router-E6FXXMMR.js → composite-router-PS42433A.js} +4 -3
  55. package/dist/consensus-vote-K2SHY4TC.js +39 -0
  56. package/dist/{consensus-vote-types-CYBHW8vY.d.ts → consensus-vote-types-Dx4pf3YW.d.ts} +16 -0
  57. package/dist/{context-retriever-I4NEOUEV.js → context-retriever-NIFXFYPQ.js} +12 -10
  58. package/dist/{dist-C4457XNQ.js → dist-KGTVHDVC.js} +4 -2
  59. package/dist/doctor-deep-VQQNT7VN.js +13 -0
  60. package/dist/{expert-bridge-GMB5IHHF.js → expert-bridge-NY6FAFQH.js} +6 -5
  61. package/dist/factory-6A26HIWS.js +15 -0
  62. package/dist/factory-GGSACEWN.js +22 -0
  63. package/dist/{improvement-review-77BKIQGN.js → improvement-review-JDSRWFHM.js} +8 -5
  64. package/dist/index.d.ts +27 -20
  65. package/dist/index.js +64 -62
  66. package/dist/index.js.map +1 -1
  67. package/dist/{init-opencode-4H2VPN23.js → init-opencode-C7U6ZQK3.js} +8 -7
  68. package/dist/{init-opencode-4H2VPN23.js.map → init-opencode-C7U6ZQK3.js.map} +1 -1
  69. package/dist/issue-triage-7RN74LBU.js +17 -0
  70. package/dist/{learning-persistence-2KO4CXNL.js → learning-persistence-EHTHKWR5.js} +3 -2
  71. package/dist/{pr-reviewer-helpers-F3SHCHNV.js → pr-reviewer-helpers-D47TVXFX.js} +6 -5
  72. package/dist/{registry-command-VFCSMHME.js → registry-command-PVC47NSQ.js} +4 -3
  73. package/dist/{registry-command-VFCSMHME.js.map → registry-command-PVC47NSQ.js.map} +1 -1
  74. package/dist/{repo-security-plan-U2ZIFW53.js → repo-security-plan-76IXMJNC.js} +5 -4
  75. package/dist/research-helpers-synthesize-WH4IC36H.js +15 -0
  76. package/dist/{routing-memory-VVLJL3MG.js → routing-memory-RAYIYIUP.js} +4 -3
  77. package/dist/{session-memory-GMQYZLJE.js → session-memory-WZCS7WDH.js} +5 -4
  78. package/dist/{setup-command-IMAX6EAO.js → setup-command-O62DVQ2U.js} +13 -12
  79. package/dist/setup-config-KEBEUMC3.js +11 -0
  80. package/dist/{setup-custom-api-NJGCRIRO.js → setup-custom-api-2PQP6UOT.js} +5 -4
  81. package/dist/{setup-custom-api-NJGCRIRO.js.map → setup-custom-api-2PQP6UOT.js.map} +1 -1
  82. package/dist/tool-memory-RAQWOUXV.js +22 -0
  83. package/dist/tool-memory-registry-adapters-Y4EGADHN.js +12 -0
  84. package/dist/unified-registry-L5PGLSEI.js +25 -0
  85. package/dist/{weather-report-OU65NJS3.js → weather-report-TEBEALS7.js} +4 -3
  86. package/dist/weather-report-TEBEALS7.js.map +1 -0
  87. package/package.json +2 -2
  88. package/dist/chunk-33MFMXBQ.js.map +0 -1
  89. package/dist/chunk-76R5ES6Z.js.map +0 -1
  90. package/dist/chunk-7TQZR5VU.js.map +0 -1
  91. package/dist/chunk-DBDWMHUL.js.map +0 -1
  92. package/dist/chunk-DLUFDKPA.js.map +0 -1
  93. package/dist/chunk-GZ4NF4ZW.js.map +0 -1
  94. package/dist/chunk-PQHVC4BD.js.map +0 -1
  95. package/dist/cli-circuit-breaker-VXBDCAD7.js +0 -13
  96. package/dist/consensus-vote-R6X5IL57.js +0 -37
  97. package/dist/doctor-deep-CZXN4YD6.js +0 -12
  98. package/dist/factory-WR62MEIJ.js +0 -14
  99. package/dist/factory-ZBQGA373.js +0 -21
  100. package/dist/issue-triage-NJB6SL4S.js +0 -16
  101. package/dist/research-helpers-synthesize-5TLNHT3I.js +0 -14
  102. package/dist/setup-config-2ZSJ3HNE.js +0 -10
  103. package/dist/tool-memory-TSYJXGOV.js +0 -20
  104. package/dist/unified-registry-IMAL3SY6.js +0 -24
  105. /package/dist/{chunk-E64SZTEP.js.map → chunk-257QMFTM.js.map} +0 -0
  106. /package/dist/{chunk-FUJ3XR7T.js.map → chunk-3AAJWZCR.js.map} +0 -0
  107. /package/dist/{chunk-Z6DXZ6AS.js.map → chunk-3JSDOBOA.js.map} +0 -0
  108. /package/dist/{chunk-FPMQ2JAK.js.map → chunk-3QH2KWLH.js.map} +0 -0
  109. /package/dist/{chunk-UDB5NHJI.js.map → chunk-4GVPON4W.js.map} +0 -0
  110. /package/dist/{chunk-QZUT22LP.js.map → chunk-5546JU53.js.map} +0 -0
  111. /package/dist/{chunk-ZMDOGN33.js.map → chunk-7E5UXA4U.js.map} +0 -0
  112. /package/dist/{chunk-F74ZGHAP.js.map → chunk-7G63H7ZT.js.map} +0 -0
  113. /package/dist/{chunk-FVSZLVMR.js.map → chunk-CQDGPGTL.js.map} +0 -0
  114. /package/dist/{chunk-MY52DFXC.js.map → chunk-FHFEC2XM.js.map} +0 -0
  115. /package/dist/{chunk-ORQAFTAZ.js.map → chunk-FIQSOSQU.js.map} +0 -0
  116. /package/dist/{chunk-EHLJLIHS.js.map → chunk-FSUZIIOJ.js.map} +0 -0
  117. /package/dist/{chunk-3EYXPV5F.js.map → chunk-GWOXPCIF.js.map} +0 -0
  118. /package/dist/{chunk-WYJJUF6N.js.map → chunk-HMZT2SJK.js.map} +0 -0
  119. /package/dist/{chunk-OCKZ6F5O.js.map → chunk-JK4L2TQ6.js.map} +0 -0
  120. /package/dist/{chunk-6UCWR3DS.js.map → chunk-JVZ7FGWR.js.map} +0 -0
  121. /package/dist/{chunk-PFBV5FCT.js.map → chunk-KOVTOPEQ.js.map} +0 -0
  122. /package/dist/{chunk-6LMZ7HFU.js.map → chunk-LCSGGLZZ.js.map} +0 -0
  123. /package/dist/{chunk-IWQH6TP7.js.map → chunk-MTE7THMR.js.map} +0 -0
  124. /package/dist/{chunk-VI7LELES.js.map → chunk-UH3F4RZB.js.map} +0 -0
  125. /package/dist/{chunk-COJOUIO2.js.map → chunk-VN3CKPEF.js.map} +0 -0
  126. /package/dist/{chunk-FSFF7EFR.js.map → chunk-VVBKPRLI.js.map} +0 -0
  127. /package/dist/{chunk-OU2NQVKD.js.map → chunk-VY4FZNZA.js.map} +0 -0
  128. /package/dist/{chunk-BTYYZ6VU.js.map → chunk-WOE5J5M6.js.map} +0 -0
  129. /package/dist/{chunk-B26FGLIJ.js.map → chunk-ZHCEOIEQ.js.map} +0 -0
  130. /package/dist/{chunk-WFKVUZ3O.js.map → chunk-ZII5MDUO.js.map} +0 -0
  131. /package/dist/{chunk-CLRSNWRQ.js.map → chunk-ZLENFXL5.js.map} +0 -0
  132. /package/dist/{cli-circuit-breaker-VXBDCAD7.js.map → cli-circuit-breaker-HFFMCA43.js.map} +0 -0
  133. /package/dist/{composite-router-E6FXXMMR.js.map → composite-router-PS42433A.js.map} +0 -0
  134. /package/dist/{consensus-vote-R6X5IL57.js.map → consensus-vote-K2SHY4TC.js.map} +0 -0
  135. /package/dist/{context-retriever-I4NEOUEV.js.map → context-retriever-NIFXFYPQ.js.map} +0 -0
  136. /package/dist/{dist-C4457XNQ.js.map → dist-KGTVHDVC.js.map} +0 -0
  137. /package/dist/{doctor-deep-CZXN4YD6.js.map → doctor-deep-VQQNT7VN.js.map} +0 -0
  138. /package/dist/{expert-bridge-GMB5IHHF.js.map → expert-bridge-NY6FAFQH.js.map} +0 -0
  139. /package/dist/{factory-WR62MEIJ.js.map → factory-6A26HIWS.js.map} +0 -0
  140. /package/dist/{factory-ZBQGA373.js.map → factory-GGSACEWN.js.map} +0 -0
  141. /package/dist/{improvement-review-77BKIQGN.js.map → improvement-review-JDSRWFHM.js.map} +0 -0
  142. /package/dist/{issue-triage-NJB6SL4S.js.map → issue-triage-7RN74LBU.js.map} +0 -0
  143. /package/dist/{learning-persistence-2KO4CXNL.js.map → learning-persistence-EHTHKWR5.js.map} +0 -0
  144. /package/dist/{pr-reviewer-helpers-F3SHCHNV.js.map → pr-reviewer-helpers-D47TVXFX.js.map} +0 -0
  145. /package/dist/{repo-security-plan-U2ZIFW53.js.map → repo-security-plan-76IXMJNC.js.map} +0 -0
  146. /package/dist/{research-helpers-synthesize-5TLNHT3I.js.map → research-helpers-synthesize-WH4IC36H.js.map} +0 -0
  147. /package/dist/{routing-memory-VVLJL3MG.js.map → routing-memory-RAYIYIUP.js.map} +0 -0
  148. /package/dist/{session-memory-GMQYZLJE.js.map → session-memory-WZCS7WDH.js.map} +0 -0
  149. /package/dist/{setup-command-IMAX6EAO.js.map → setup-command-O62DVQ2U.js.map} +0 -0
  150. /package/dist/{setup-config-2ZSJ3HNE.js.map → setup-config-KEBEUMC3.js.map} +0 -0
  151. /package/dist/{tool-memory-TSYJXGOV.js.map → tool-memory-RAQWOUXV.js.map} +0 -0
  152. /package/dist/{unified-registry-IMAL3SY6.js.map → tool-memory-registry-adapters-Y4EGADHN.js.map} +0 -0
  153. /package/dist/{weather-report-OU65NJS3.js.map → unified-registry-L5PGLSEI.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp/tools/improvement-review.ts","../src/mcp/middleware/tool-prerequisites.ts","../src/governance/fitness-score.ts","../src/mcp/tools/improvement-review-signals.ts","../src/mcp/tools/improvement-review-tool-fitness-heuristics.ts","../src/governance/tool-fitness-ledger.ts","../src/mcp/tools/improvement-review-tool-fitness.ts","../src/mcp/tools/improvement-review-perf-regression.ts","../src/mcp/tools/improvement-remediation.ts","../src/mcp/tools/improvement-remediation-shadow.ts","../src/mcp/tools/diff-secret-scan.ts","../src/mcp/tools/remediation-priority.ts"],"sourcesContent":["/**\n * nexus-agents/mcp - Improvement Review Tool\n *\n * Periodic, threshold-gated observability-driven improvement loop.\n *\n * Reads from existing observability primitives (OutcomeStore, weather-report,\n * fitness-audit, audit-chain) and surfaces patterns that cross documented\n * thresholds as candidate GitHub issues. Never auto-merges; humans or\n * `consensus_vote` decide what to implement.\n *\n * Replaces the deleted `src/workflows/self-development/` engine, which never\n * wired up to consume any of these signals.\n *\n * @module mcp/tools/improvement-review\n * (Source: Issue #2402)\n */\n\nimport { execFile } from 'node:child_process';\nimport { readFile } from 'node:fs/promises';\nimport { promisify } from 'node:util';\n/* eslint-disable max-lines */\nimport { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { createLogger, formatZodError, getErrorMessage, type ILogger } from '../../core/index.js';\nimport { wrapToolWithTimeout, toSdkCallback, getToolTimeout } from '../middleware/tool-wrapper.js';\nimport { createSecureHandler, type HandlerContext } from '../middleware/secure-handler.js';\nimport { withPrerequisite } from '../middleware/tool-prerequisites.js';\nimport {\n toolStructuredError,\n toolSuccessStructured,\n type ToolResult,\n type BaseMcpToolDeps,\n} from './tool-result.js';\nimport { getOutcomeStore } from '../../orchestration/outcomes/outcome-store.js';\nimport type { TaskOutcome } from '../../orchestration/outcomes/outcome-types.js';\nimport { createHash } from 'node:crypto';\nimport {\n calculateFitnessScore,\n FITNESS_DIMENSION_MAX,\n type FitnessAudit,\n type FitnessDimension,\n type FitnessFinding,\n} from '../../governance/fitness-score.js';\nimport { getPipelineEventBus } from '../../pipeline/event-bus.js';\nimport type { VoteRejectedSignalEvent } from '../../pipeline/event-types.js';\nimport { REJECTION_CATEGORIES } from '../../consensus/types-core.js';\nimport { emitFitnessDeclinedSignal } from './improvement-review-signals.js';\nimport { loadToolFitnessSignals } from './improvement-review-tool-fitness.js';\nimport {\n detectPerfRegressionSignals,\n type PerfBaselineMap,\n} from './improvement-review-perf-regression.js';\nimport type { BenchmarkSuiteResult } from '../../benchmarks/benchmark-types.js';\nimport { improvementSignalsToTasks } from './improvement-remediation.js';\nimport { recordRemediationShadow } from './improvement-remediation-shadow.js';\nimport { classifySignalPriority, priorityLabel } from './remediation-priority.js';\nimport type { PipelineTask } from '../../pipeline/dev-pipeline.js';\nimport { getToolAnnotations } from '../tool-annotations.js';\n\nconst execFileAsync = promisify(execFile);\n\n// ============================================================================\n// Schemas\n// ============================================================================\n\nexport const ImprovementReviewInputSchema = z.object({\n lookbackDays: z\n .number()\n .int()\n .min(1)\n .max(90)\n .optional()\n .default(7)\n .describe('Lookback window for outcome data, in days. Default 7.'),\n fileIssues: z\n .boolean()\n .optional()\n .default(false)\n .describe(\n 'When true, file candidate issues via `gh issue create` for crossed thresholds (rate-limited to 5 per run, deduped against open issues). When false (default), return signals only.'\n ),\n minSampleSize: z\n .number()\n .int()\n .min(1)\n .max(1000)\n .optional()\n .default(5)\n .describe('Minimum sample size before a CLI/category signal can fire.'),\n fitnessFloor: z\n .number()\n .int()\n .min(0)\n .max(100)\n .optional()\n .default(90)\n .describe('Fitness score below this threshold triggers a tech-debt signal.'),\n selfEvalReportPath: z\n .string()\n .optional()\n .describe(\n 'Optional path to a self-eval JSON report (from `self-eval --json`). When set, ' +\n 'high-confidence unanimous deprecate/refactor findings are surfaced as tech-debt ' +\n 'signals through the same deduped/rate-limited issue path (#3224). Unreadable/malformed ' +\n 'reports are skipped (no signal). Absent → no self-eval signals.'\n ),\n});\n\nexport type ImprovementReviewInput = z.infer<typeof ImprovementReviewInputSchema>;\n\nexport type SignalCategory =\n | 'routing'\n | 'tech-debt'\n | 'bug'\n | 'security'\n | 'consensus'\n // #3852 (closes the #3692 sequencing): tool-fitness deprecation/consolidation\n // candidates from the #3851 ledger. SUGGEST-TIER ONLY — never autonomous\n // removal (Epic F invariant). See improvement-review-tool-fitness.ts.\n | 'tool-fitness'\n // #3692 + #3246 (Option A): deterministic benchmark perf regression vs a\n // STATIC, pinned baseline + fixed tolerance. SURFACED-ONLY — never auto-applies\n // a fitness/governance penalty. The static baseline keeps this out of the\n // deferred #3230 adaptive-control scope. See improvement-review-perf-regression.ts.\n | 'perf-regression';\n\nexport interface ImprovementSignal {\n readonly category: SignalCategory;\n /** Stable key used for dedup against existing issues. */\n readonly signalKey: string;\n /** Severity per CVSS-aligned scale (security uses critical; others use warning/info). */\n readonly severity: 'info' | 'warning' | 'critical';\n /** One-line title suitable for a GitHub issue. */\n readonly title: string;\n /** Multi-line body with evidence (sample counts, time windows, observed values). */\n readonly body: string;\n /** Linkable evidence the signal is grounded in observability data, not intuition. */\n readonly evidence: {\n readonly samples?: number;\n readonly window?: string;\n readonly observedValue?: number;\n readonly threshold?: number;\n };\n}\n\nexport interface ImprovementReviewResponse {\n readonly window: string;\n readonly totalOutcomes: number;\n readonly signals: readonly ImprovementSignal[];\n /**\n * Remediation tasks derived from {@link signals} (#3540 capability-loop\n * increment 1) — SUGGEST-ONLY: structured tasks for a reviewer to consider\n * routing through the dev-pipeline. Nothing here is executed or auto-invoked.\n */\n readonly remediationTasks: readonly PipelineTask[];\n readonly issuesFiled: readonly { readonly signalKey: string; readonly issueUrl: string }[];\n readonly issuesSkipped: readonly { readonly signalKey: string; readonly reason: string }[];\n}\n\n// ============================================================================\n// Pure threshold logic (testable without fs / network)\n// ============================================================================\n\nconst MAX_ISSUES_PER_RUN = 5;\n\nconst HOUR_MS = 60 * 60 * 1000;\nconst DAY_MS = 24 * HOUR_MS;\n\n/** Filter outcomes to a lookback window. Outcome timestamps are ISO strings. */\nexport function filterByLookback(\n outcomes: readonly TaskOutcome[],\n lookbackDays: number,\n now: number\n): readonly TaskOutcome[] {\n const cutoff = now - lookbackDays * DAY_MS;\n return outcomes.filter((o) => {\n const t = Date.parse(o.timestamp);\n return Number.isFinite(t) && t >= cutoff;\n });\n}\n\n/**\n * Infrastructure/transport failure categories — NOT model reasoning quality\n * (#3620). These are excluded from the CLI performance-floor so the routing\n * signal measures whether the MODEL does the task, not whether the adapter was\n * reachable. Adapter outages / empty responses still surface separately via\n * {@link detectFailureCategoryConcentration}, so excluding them here doesn't hide\n * them — it just stops them being mislabeled as a CLI quality regression.\n */\nconst INFRA_FAILURE_CATEGORIES: ReadonlySet<string> = new Set([\n 'timeout',\n 'authentication',\n 'rate_limit',\n 'connection',\n 'adapter_unavailable',\n 'parse',\n]);\n\n/**\n * Detect CLI × category pairs whose MODEL-QUALITY success rate has fallen below\n * the performance floor with at least minSamples observations.\n *\n * Threshold: quality success rate < 60% AND quality-samples >= minSamples.\n * Infra/transport failures (adapter_unavailable, parse/empty-response, auth,\n * rate-limit, timeout, connection) are excluded from the rate (#3620) — they are\n * availability problems, not model quality, and surface via the failure-category\n * concentration detector instead.\n */\ninterface QualityBucket {\n cli: string;\n category: string;\n ok: number;\n total: number;\n infra: number;\n}\n\n/**\n * Models/clis that don't identify a real executor (#3624) — outcomes with these\n * can't be attributed to a CLI's quality, so they're excluded from the floor\n * (else the skew just moves from a real CLI onto an `unknown`/placeholder one).\n */\nconst UNATTRIBUTED_VALUES: ReadonlySet<string> = new Set([\n '',\n 'unknown',\n 'expert',\n 'heuristic',\n 'default',\n]);\n\n/** Bucket outcomes by cli×category, separating infra failures from quality ones. */\nfunction accumulateQualityBuckets(outcomes: readonly TaskOutcome[]): Map<string, QualityBucket> {\n const buckets = new Map<string, QualityBucket>();\n for (const o of outcomes) {\n // Skip outcomes that can't attribute a real executing CLI (#3624).\n if (UNATTRIBUTED_VALUES.has(o.cli) || UNATTRIBUTED_VALUES.has(o.model)) continue;\n const key = `${o.cli}::${o.category}`;\n const b = buckets.get(key) ?? { cli: o.cli, category: o.category, ok: 0, total: 0, infra: 0 };\n if (!o.success && INFRA_FAILURE_CATEGORIES.has(o.failureCategory ?? '')) {\n b.infra += 1; // infra/transport failure — excluded from the quality rate\n } else {\n b.total += 1;\n if (o.success) b.ok += 1;\n }\n buckets.set(key, b);\n }\n return buckets;\n}\n\n/** Build a performance-floor signal for a below-floor quality bucket. */\nfunction floorSignalFromBucket(\n b: QualityBucket,\n minSamples: number,\n windowLabel: string\n): ImprovementSignal {\n const rate = b.ok / b.total;\n const ratePct = Math.round(rate * 100);\n const infraNote =\n b.infra > 0\n ? ` (${String(b.infra)} infra/transport failures excluded — see failure-concentration signals)`\n : '';\n return {\n category: 'routing',\n signalKey: `routing:cli-floor:${b.cli}:${b.category}`,\n severity: rate < 0.4 ? 'critical' : 'warning',\n title: `routing: ${b.cli} model-quality success ${String(ratePct)}% on ${b.category} (${windowLabel})`,\n body: [\n `Observed model-quality performance floor breach in the ${windowLabel} window.`,\n '',\n `- CLI: \\`${b.cli}\\``,\n `- Category: \\`${b.category}\\``,\n `- Quality success rate: ${String(ratePct)}% (${String(b.ok)}/${String(b.total)})${infraNote}`,\n `- Threshold: 60% with ≥${String(minSamples)} quality samples`,\n '',\n 'Quality failures only (infra/transport excluded). Consider routing this category away from this CLI, or investigating the failure pattern via `weather_report` and the OutcomeStore.',\n ].join('\\n'),\n evidence: { samples: b.total, window: windowLabel, observedValue: rate, threshold: 0.6 },\n };\n}\n\nexport function detectCliPerformanceFloor(\n outcomes: readonly TaskOutcome[],\n minSamples: number,\n windowLabel: string\n): readonly ImprovementSignal[] {\n const signals: ImprovementSignal[] = [];\n for (const b of accumulateQualityBuckets(outcomes).values()) {\n if (b.total < minSamples) continue;\n if (b.ok / b.total >= 0.6) continue;\n signals.push(floorSignalFromBucket(b, minSamples, windowLabel));\n }\n return signals;\n}\n\n/**\n * Minimum number of rejected plans citing the same ADR-0016 rule before a\n * recurring-rejection pattern is worth surfacing. Two is coincidence; three is\n * a systemic planning gap (mirrors the DRY \"third occurrence\" rule).\n */\nconst MIN_REJECTION_PATTERN = 3;\n\n/**\n * Detect recurring consensus-rejection patterns (#3259): a single ADR-0016\n * rejection rule (`DRY_VIOLATION`, `OVER_ENGINEERING`, `SCOPE_CREEP`, …) cited\n * across ≥{@link MIN_REJECTION_PATTERN} rejected plans in the window. The\n * `signal.vote_rejected` events are produced by `consensus_vote` on rejection\n * (consensus-vote-signals.ts) and buffered on the pipeline event bus; this\n * detector closes the loop the system review flagged as missing — recurring\n * rejection for the same reason means the planner keeps making the same class\n * of mistake, which the next improvement cycle should name explicitly.\n *\n * Events with no `rejectionRules` (un-categorized rejections) contribute no\n * pattern signal — there is nothing actionable to aggregate on.\n */\nexport function detectConsensusRejectionSignals(\n events: readonly VoteRejectedSignalEvent[],\n windowLabel: string\n): readonly ImprovementSignal[] {\n if (events.length === 0) return [];\n\n // Defense-in-depth allowlist: the only producer (consensus-vote-signals.ts)\n // sources rules from the Zod-validated ADR-0016 enum, so a free-form/poisoned\n // rule cannot reach here today. Re-validating against REJECTION_CATEGORIES\n // makes that safety local — an unexpected rule string never reaches an issue\n // title/body — instead of relying on cross-file inference (#3259 review).\n const allowed = new Set<string>(REJECTION_CATEGORIES);\n const byRule = new Map<string, number>();\n for (const e of events) {\n for (const rule of e.rejectionRules ?? []) {\n if (!allowed.has(rule)) continue;\n byRule.set(rule, (byRule.get(rule) ?? 0) + 1);\n }\n }\n\n const signals: ImprovementSignal[] = [];\n for (const [rule, count] of byRule) {\n if (count < MIN_REJECTION_PATTERN) continue;\n signals.push({\n category: 'consensus',\n signalKey: `consensus:rejection-pattern:${rule}`,\n severity: count >= MIN_REJECTION_PATTERN * 2 ? 'warning' : 'info',\n title: `consensus: ${String(count)} plans rejected for \\`${rule}\\` in ${windowLabel}`,\n body: [\n `Recurring consensus-rejection pattern in the ${windowLabel} window.`,\n '',\n `- Rejection rule: \\`${rule}\\` (ADR-0016 category)`,\n `- Occurrences: ${String(count)} rejected plans`,\n `- Threshold: ≥${String(MIN_REJECTION_PATTERN)} plans citing the same rule`,\n '',\n 'The planner keeps producing plans that voters reject for the same reason. ' +\n 'Feed this back into plan generation (e.g. a planning guardrail or a ' +\n 'targeted prompt note) rather than rejecting plan-by-plan. Inspect the ' +\n 'rejected proposals via `query_trace` / the consensus audit chain.',\n ].join('\\n'),\n evidence: {\n samples: count,\n window: windowLabel,\n observedValue: count,\n threshold: MIN_REJECTION_PATTERN,\n },\n });\n }\n return signals;\n}\n\n/**\n * Detect failure-category concentration: a single failure category accounts\n * for > 50% of all failures with at least 10 failures observed.\n */\nexport function detectFailureCategoryConcentration(\n outcomes: readonly TaskOutcome[],\n windowLabel: string\n): readonly ImprovementSignal[] {\n const failures = outcomes.filter((o) => !o.success);\n if (failures.length < 10) return [];\n\n const byCategory = new Map<string, number>();\n for (const f of failures) {\n const cat = f.failureCategory ?? 'unknown';\n byCategory.set(cat, (byCategory.get(cat) ?? 0) + 1);\n }\n\n const signals: ImprovementSignal[] = [];\n for (const [cat, count] of byCategory) {\n const share = count / failures.length;\n if (share <= 0.5) continue;\n const sharePct = Math.round(share * 100);\n signals.push({\n category: 'bug',\n signalKey: `bug:failure-concentration:${cat}`,\n severity: 'warning',\n title: `bug: ${String(sharePct)}% of failures in ${windowLabel} share category \\`${cat}\\``,\n body: [\n `Failure-category concentration breach in the ${windowLabel} window.`,\n '',\n `- Category: \\`${cat}\\``,\n `- Share: ${String(sharePct)}% (${String(count)}/${String(failures.length)} failures)`,\n `- Threshold: > 50% with ≥10 failures`,\n '',\n 'A single failure mode dominating the error budget usually means a systemic bug or routing miss. Investigate via `query_trace` and the OutcomeStore.',\n ].join('\\n'),\n evidence: {\n samples: failures.length,\n window: windowLabel,\n observedValue: share,\n threshold: 0.5,\n },\n });\n }\n return signals;\n}\n\nfunction buildFloorSignal(audit: FitnessAudit, fitnessFloor: number): ImprovementSignal {\n return {\n category: 'tech-debt',\n signalKey: `tech-debt:fitness-below-floor`,\n severity: audit.score < 70 ? 'critical' : 'warning',\n title: `tech-debt: fitness score ${String(audit.score)}/100 below floor ${String(fitnessFloor)}`,\n body: [\n `Code fitness score has dropped below the governance floor.`,\n '',\n `- Score: ${String(audit.score)} / 100`,\n `- Floor: ${String(fitnessFloor)} (governance threshold per CLAUDE.md)`,\n `- Findings: ${String(audit.findings.length)} total`,\n '',\n 'Run `nexus-agents fitness-audit` for the full breakdown. Critical findings:',\n ...audit.findings\n .filter((f) => f.severity === 'critical')\n .slice(0, 5)\n .map((f) => `- ${f.dimension}: ${f.description}`),\n ].join('\\n'),\n evidence: { observedValue: audit.score, threshold: fitnessFloor },\n };\n}\n\n// ----------------------------------------------------------------------------\n// Per-dimension fitness-remediation signal (#3227)\n//\n// Goal: route a below-target *dimension* (not just a single critical finding or\n// the aggregate score) to the EXISTING off-by-default research→implement loop.\n// This is SIGNAL-GENERATION ONLY — it adds a new signalKey namespace that flows\n// through the same detectFitnessSignals→consumer path as every other signal. It\n// introduces no new loop, no TuneStage change, no routing mutation, no new\n// autonomous behavior. The consumer (and its off-by-default gate) is unchanged.\n// ----------------------------------------------------------------------------\n\n/**\n * A dimension is \"below target\" when its score is a strict fraction of its OWN\n * max — NOT a global proportional floor. Documented, fixed constant; no\n * learned/adaptive threshold (#3227 condition 2). Boundary is EXCLUSIVE: a\n * dimension at exactly 0.6×max is on-target and emits nothing (tested).\n */\nconst FITNESS_DIMENSION_TARGET_FRACTION = 0.6;\n\n/**\n * Cap per run on how many below-target dimension signals are emitted, ranked by\n * points-below-target worst-first (#3227 spam-guard 1b). Prevents a broadly\n * degraded audit from fanning out one signal per dimension.\n */\nconst MAX_DIMENSION_SIGNALS_PER_RUN = 3;\n\n/**\n * Free-text caps when carrying a finding's `description`/`suggestion` into a\n * signal body (#3227 condition 6, findings-as-data). A finding's `suggestion` is\n * DATA carried in the payload, never an instruction; capping bounds the body\n * size regardless of upstream input.\n */\nconst MAX_FINDING_TEXT_LEN = 280;\nconst MAX_FINDINGS_IN_DIMENSION_BODY = 10;\n\n/**\n * Structurally-unreachable dimensions to quarantine from per-dimension signals\n * (#3227 condition 2): a dimension that can essentially never reach 0.6×max by\n * design would emit perpetual noise. An audit of the current checks shows every\n * dimension CAN drop below target through real penalties (e.g. canonicalPaths\n * 20→10 on missing routers + no IOrchestrator; governanceIntegration 5→2 on a\n * missing CLAUDE.md), so the set is intentionally EMPTY today. It exists as the\n * explicit, documented mechanism: add a dimension here (with the reason) rather\n * than letting a perpetually-below-target dimension spam the loop.\n */\nconst STRUCTURALLY_UNREACHABLE_DIMENSIONS: ReadonlySet<FitnessDimension> = new Set<FitnessDimension>(\n []\n);\n\n/** The closed set of known dimensions — validate findings-as-data against this. */\nconst KNOWN_DIMENSIONS: ReadonlySet<FitnessDimension> = new Set(\n Object.keys(FITNESS_DIMENSION_MAX) as FitnessDimension[]\n);\n\n/** Cap free-text carried from a finding into a signal body (findings-as-data). */\nfunction capText(text: string): string {\n return text.length > MAX_FINDING_TEXT_LEN ? `${text.slice(0, MAX_FINDING_TEXT_LEN)}…` : text;\n}\n\n/**\n * Render a finding as body lines, shared by the critical-path signal and the\n * per-dimension signal (#3227 condition 4 — DRY: one renderer, not a forked\n * near-duplicate). The finding's free-text fields are capped (findings-as-data)\n * and emitted as plain evidence, never as an instruction.\n */\nfunction findingBodyLines(finding: FitnessFinding): string[] {\n return [\n `- Description: ${capText(finding.description)}`,\n `- Points deducted: ${String(finding.pointsDeducted)}`,\n finding.location !== undefined ? `- Location: ${capText(finding.location)}` : '',\n finding.suggestion !== undefined ? `- Suggestion: ${capText(finding.suggestion)}` : '',\n ].filter((line) => line.length > 0);\n}\n\n/**\n * A stable identifier for a finding, used both for the per-dimension dedup key\n * and the floor cross-reference. There is no explicit finding id on\n * {@link FitnessFinding}, so derive a deterministic one from its stable fields.\n */\nfunction findingIdentifier(finding: FitnessFinding): string {\n return `${finding.dimension}|${finding.severity}|${finding.description}|${finding.location ?? ''}`;\n}\n\nfunction buildCriticalFindingSignal(finding: FitnessFinding): ImprovementSignal {\n return {\n category: 'tech-debt',\n signalKey: `tech-debt:fitness-critical:${finding.dimension}`,\n severity: 'critical',\n title: `tech-debt: critical fitness finding in ${finding.dimension}`,\n body: [`Fitness audit returned a CRITICAL finding.`, '', `- Dimension: \\`${finding.dimension}\\``, ...findingBodyLines(finding)].join(\n '\\n'\n ),\n evidence: { observedValue: -finding.pointsDeducted },\n };\n}\n\ninterface DimensionBreach {\n readonly dimension: FitnessDimension;\n readonly score: number;\n readonly max: number;\n readonly target: number;\n /** How far below target, in points — the ranking key for the top-3 cap. */\n readonly pointsBelowTarget: number;\n readonly findings: readonly FitnessFinding[];\n}\n\n/**\n * A below-target dimension is one whose score is strictly below\n * {@link FITNESS_DIMENSION_TARGET_FRACTION}×max, is a KNOWN dimension, and is not\n * structurally-quarantined. Returns the breaches sorted deterministically\n * worst-first (pointsBelowTarget desc, then dimension name) so the top-3 cap and\n * the emitted order are stable for identical input (#3227 determinism).\n */\nfunction detectDimensionBreaches(audit: FitnessAudit): readonly DimensionBreach[] {\n const findingsByDimension = new Map<FitnessDimension, FitnessFinding[]>();\n for (const f of audit.findings) {\n // Findings-as-data (#3227 condition 6): only aggregate findings whose\n // dimension is in the closed, known set — never trust a free-form string.\n if (!KNOWN_DIMENSIONS.has(f.dimension)) continue;\n const list = findingsByDimension.get(f.dimension) ?? [];\n list.push(f);\n findingsByDimension.set(f.dimension, list);\n }\n\n const breaches: DimensionBreach[] = [];\n for (const dimension of KNOWN_DIMENSIONS) {\n if (STRUCTURALLY_UNREACHABLE_DIMENSIONS.has(dimension)) continue;\n const max = FITNESS_DIMENSION_MAX[dimension];\n const score = audit.dimensions[dimension];\n // A dimension absent from the audit's dimensions map (e.g. the fallback\n // empty-object audit) has no measured score — skip rather than treat as 0.\n if (typeof score !== 'number') continue;\n const target = FITNESS_DIMENSION_TARGET_FRACTION * max;\n if (score >= target) continue; // exclusive boundary: exactly target is on-target\n breaches.push({\n dimension,\n score,\n max,\n target,\n pointsBelowTarget: target - score,\n findings: findingsByDimension.get(dimension) ?? [],\n });\n }\n\n breaches.sort(\n (a, b) => b.pointsBelowTarget - a.pointsBelowTarget || a.dimension.localeCompare(b.dimension)\n );\n return breaches;\n}\n\n/**\n * Build ONE aggregated signal for a below-target dimension (#3227 condition 1a —\n * never one-signal-per-finding). The signalKey carries a stable dedup hash of\n * `(dimension + sorted finding identifiers)` so an UNCHANGED dimension produces\n * the SAME key across runs and the existing consumer dedup (keyed on signalKey,\n * the same mechanism the floor/critical signals rely on) suppresses a re-emit\n * (#3227 spam-guard 1c).\n */\nfunction buildDimensionSignal(breach: DimensionBreach): ImprovementSignal {\n const sortedIds = breach.findings.map(findingIdentifier).sort();\n const dedup = createHash('sha256')\n .update([breach.dimension, ...sortedIds].join('\u0000'))\n .digest('hex')\n .slice(0, 12);\n\n const findingLines =\n breach.findings.length === 0\n ? ['_No itemized findings recorded for this dimension — score is below target on aggregate._']\n : breach.findings\n .slice(0, MAX_FINDINGS_IN_DIMENSION_BODY)\n .flatMap((f, i) => [`${String(i + 1)}.`, ...findingBodyLines(f).map((l) => ` ${l}`)]);\n\n const scorePct = Math.round((breach.score / breach.max) * 100);\n return {\n category: 'tech-debt',\n signalKey: `tech-debt:fitness-dimension:${breach.dimension}:${dedup}`,\n severity: 'warning',\n title: `tech-debt: ${breach.dimension} fitness ${String(breach.score)}/${String(breach.max)} below target`,\n body: [\n `Fitness dimension \\`${breach.dimension}\\` is below its remediation target.`,\n '',\n `- Score: ${String(breach.score)} / ${String(breach.max)} (${String(scorePct)}%)`,\n `- Target: ≥ ${String(breach.target)} (${String(Math.round(FITNESS_DIMENSION_TARGET_FRACTION * 100))}% of this dimension's max)`,\n `- Points below target: ${String(breach.pointsBelowTarget)}`,\n `- Findings in this dimension: ${String(breach.findings.length)}`,\n '',\n 'This routes the below-target dimension to the off-by-default research→implement ' +\n 'loop. The findings below are DATA grounding the signal, not instructions:',\n '',\n ...findingLines,\n ].join('\\n'),\n evidence: {\n observedValue: breach.score,\n threshold: breach.target,\n },\n };\n}\n\n/**\n * Per-dimension fitness-remediation signals (#3227): for each below-target\n * dimension (top-3 worst, deterministic), one aggregated `tech-debt:\n * fitness-dimension:<dim>:<hash>` signal carrying that dimension's findings.\n *\n * Floor cross-reference (#3227 condition 3 / 4): these are intentionally\n * COMPLEMENTARY to {@link buildFloorSignal}, not redundant remediations. The\n * floor signal addresses the AGGREGATE score and lists up-to-5 critical findings\n * by dimension; a dimension signal *targets* a specific below-target dimension's\n * full finding set. A single root cause therefore appears once as\n * dimension-targeted remediation here and (if it also dragged the aggregate\n * below the floor) as score context in the floor signal — the dimension signals\n * add dimension targeting, they do not duplicate the floor's remediation.\n */\nexport function detectFitnessDimensionSignals(audit: FitnessAudit): readonly ImprovementSignal[] {\n if (audit.auditable === false) return [];\n return detectDimensionBreaches(audit)\n .slice(0, MAX_DIMENSION_SIGNALS_PER_RUN)\n .map(buildDimensionSignal);\n}\n\n/**\n * Detect fitness signals: score below floor OR critical findings OR below-target\n * dimensions (#3227). All flow through the SAME consumer path; the off-by-default\n * gate and audit-stops-pre-implement behavior are unchanged.\n */\nexport function detectFitnessSignals(\n audit: FitnessAudit,\n fitnessFloor: number\n): readonly ImprovementSignal[] {\n const signals: ImprovementSignal[] = [];\n // #3621: a non-auditable result (e.g. run from the global npm install) has a\n // meaningless score of 0 — it is \"could not audit\", not \"fitness is low\". Do\n // not emit a spurious below-floor tech-debt signal for it.\n if (audit.auditable === false) return signals;\n if (audit.score < fitnessFloor) signals.push(buildFloorSignal(audit, fitnessFloor));\n for (const finding of audit.findings) {\n if (finding.severity === 'critical') signals.push(buildCriticalFindingSignal(finding));\n }\n signals.push(...detectFitnessDimensionSignals(audit));\n return signals;\n}\n\n// ============================================================================\n// Self-eval findings → tech-debt signals (#3224)\n// ============================================================================\n\n/** Minimum confidence for a self-eval finding to surface as a signal. */\nconst SELF_EVAL_CONFIDENCE_FLOOR = 0.8;\n\n/**\n * Minimal, defensive schema for the `self-eval --json` report. We only read the\n * fields needed to surface a finding; unknown extras are ignored so the parse\n * tolerates schema drift in the (externally produced) artifact.\n */\nconst SelfEvalReportSchema = z.object({\n results: z.array(\n z.object({\n component: z.string(),\n finalRecommendation: z.string(),\n confidence: z.number(),\n dissent: z.array(z.unknown()).optional().default([]),\n evidenceQuality: z.number().optional(),\n })\n ),\n});\n\n/**\n * Convert a parsed self-eval report into tech-debt `ImprovementSignal`s.\n *\n * Only **actionable, high-confidence, unanimous** findings surface (#3224): a\n * `deprecate`/`refactor` recommendation with NO dissent and confidence at/above\n * {@link SELF_EVAL_CONFIDENCE_FLOOR}. This is a pure transform — it surfaces a\n * human decision point (a candidate issue), never an automatic routing change.\n */\nexport function detectSelfEvalSignals(\n report: z.infer<typeof SelfEvalReportSchema>,\n windowLabel: string\n): readonly ImprovementSignal[] {\n const signals: ImprovementSignal[] = [];\n for (const r of report.results) {\n const actionable =\n r.finalRecommendation === 'deprecate' || r.finalRecommendation === 'refactor';\n if (!actionable || r.dissent.length > 0 || r.confidence < SELF_EVAL_CONFIDENCE_FLOOR) continue;\n signals.push({\n category: 'tech-debt',\n signalKey: `tech-debt:self-eval:${r.component}:${r.finalRecommendation}`,\n severity: r.finalRecommendation === 'deprecate' ? 'warning' : 'info',\n title: `tech-debt: self-eval recommends ${r.finalRecommendation} for ${r.component}`,\n body: [\n `All self-eval evaluators agreed (no dissent) on **${r.finalRecommendation}** for \\`${r.component}\\``,\n `with confidence ${(r.confidence * 100).toFixed(0)}%${r.evidenceQuality !== undefined ? ` (evidence quality ${(r.evidenceQuality * 100).toFixed(0)}%)` : ''}.`,\n '',\n 'This is a RECOMMENDATION surfaced for human review — not an automatic change.',\n ].join('\\n'),\n evidence: {\n observedValue: r.confidence,\n threshold: SELF_EVAL_CONFIDENCE_FLOOR,\n window: windowLabel,\n },\n });\n }\n return signals;\n}\n\n/**\n * Read + parse a self-eval JSON report and convert it to signals. Fail-soft:\n * an unreadable or malformed report yields NO signals (logged at warn) rather\n * than breaking the review.\n */\nexport async function loadSelfEvalSignals(\n reportPath: string,\n windowLabel: string,\n logger: ReturnType<typeof createLogger>\n): Promise<readonly ImprovementSignal[]> {\n try {\n const raw = await readFile(reportPath, 'utf8');\n const parsed = SelfEvalReportSchema.safeParse(JSON.parse(raw));\n if (!parsed.success) {\n logger.warn('Self-eval report ignored — schema mismatch', {\n reportPath,\n error: formatZodError(parsed.error),\n });\n return [];\n }\n return detectSelfEvalSignals(parsed.data, windowLabel);\n } catch (error) {\n logger.warn('Self-eval report ignored — unreadable/invalid JSON', {\n reportPath,\n error: getErrorMessage(error),\n });\n return [];\n }\n}\n\n// ============================================================================\n// Issue filing (gated, dedup-checked, command-injection-safe)\n// ============================================================================\n\n/**\n * Check whether an existing OPEN issue already covers this signal key.\n * Uses `gh issue list --search` with the signal key as a literal phrase.\n * The signal key appears in our filed-issue body so this dedup is reliable.\n */\nasync function existingIssueForSignal(signalKey: string): Promise<string | null> {\n try {\n // Strip double-quotes from the search term so a quote in the signalKey\n // (e.g. an oddly-named self-eval component path, #3224) can't break the\n // `\"...\" in:body` phrase query and silently defeat dedup → refiling.\n const searchTerm = signalKey.replace(/\"/g, '');\n const { stdout } = await execFileAsync('gh', [\n 'issue',\n 'list',\n '--state',\n 'open',\n '--search',\n `\"${searchTerm}\" in:body`,\n '--json',\n 'number,url',\n '--limit',\n '5',\n ]);\n const parsed = JSON.parse(stdout) as readonly { url?: string }[];\n if (parsed.length > 0 && typeof parsed[0]?.url === 'string') {\n return parsed[0].url;\n }\n return null;\n } catch {\n // gh failure → conservatively treat as \"no dup\" but log upstream.\n return null;\n }\n}\n\n/**\n * Labels for an auto-filed signal issue (#3653): the p0–p4 priority (computed by\n * {@link classifySignalPriority} from TYPED signal fields — security is always p0,\n * fail-closed; never taken from untrusted input, so an issue cannot steer its own\n * tag) plus the signal category. The priority drives the consensus rigor the\n * auto-remediation path later requires for this issue.\n */\nexport function issueLabelsForSignal(signal: ImprovementSignal): readonly string[] {\n return [priorityLabel(classifySignalPriority(signal)), signal.category];\n}\n\n/**\n * File an issue via `gh issue create` using execFile (no shell, no\n * command-injection risk on errorMessage / title / body content).\n */\nasync function fileIssueForSignal(\n signal: ImprovementSignal\n): Promise<{ ok: true; url: string } | { ok: false; error: string }> {\n // Embed the signal key in the body so dedup is reliable on subsequent runs.\n const body = `${signal.body}\\n\\n---\\n\\n_Signal key (do not edit): \\`${signal.signalKey}\\` · Generated by \\`improvement_review\\` (#2402) · Severity: ${signal.severity}_`;\n\n try {\n const { stdout } = await execFileAsync('gh', [\n 'issue',\n 'create',\n '--title',\n signal.title,\n '--body',\n body,\n '--label',\n issueLabelsForSignal(signal).join(','),\n ]);\n const url = stdout.trim();\n if (!url.startsWith('https://')) {\n return { ok: false, error: `gh returned unexpected output: ${stdout.slice(0, 200)}` };\n }\n return { ok: true, url };\n } catch (caught) {\n const message = caught instanceof Error ? caught.message : String(caught);\n return { ok: false, error: message };\n }\n}\n\n// ============================================================================\n// Handler\n// ============================================================================\n\nfunction safeFitnessAudit(now: number, ctx: HandlerContext): FitnessAudit {\n try {\n return calculateFitnessScore('improvement-review');\n } catch (caught) {\n ctx.logger.warn('fitness audit failed; skipping fitness signals', {\n error: caught instanceof Error ? caught.message : String(caught),\n });\n return {\n score: 100,\n dimensions: {} as FitnessAudit['dimensions'],\n findings: [],\n timestamp: new Date(now).toISOString(),\n version: 'improvement-review-fallback',\n };\n }\n}\n\nconst SEVERITY_ORDER: Record<ImprovementSignal['severity'], number> = {\n critical: 0,\n warning: 1,\n info: 2,\n};\n\nasync function fileSignalsAsIssues(\n signals: readonly ImprovementSignal[],\n ctx: HandlerContext\n): Promise<{\n issuesFiled: { signalKey: string; issueUrl: string }[];\n issuesSkipped: { signalKey: string; reason: string }[];\n}> {\n const issuesFiled: { signalKey: string; issueUrl: string }[] = [];\n const issuesSkipped: { signalKey: string; reason: string }[] = [];\n\n for (const signal of signals) {\n if (issuesFiled.length >= MAX_ISSUES_PER_RUN) {\n issuesSkipped.push({ signalKey: signal.signalKey, reason: 'rate-limit' });\n continue;\n }\n const existing = await existingIssueForSignal(signal.signalKey);\n if (existing !== null) {\n issuesSkipped.push({ signalKey: signal.signalKey, reason: `dup:${existing}` });\n continue;\n }\n const result = await fileIssueForSignal(signal);\n if (result.ok) {\n issuesFiled.push({ signalKey: signal.signalKey, issueUrl: result.url });\n ctx.logger.info('improvement signal filed', {\n signalKey: signal.signalKey,\n url: result.url,\n });\n } else {\n issuesSkipped.push({ signalKey: signal.signalKey, reason: `error:${result.error}` });\n }\n }\n\n return { issuesFiled, issuesSkipped };\n}\n\n/**\n * Read `signal.vote_rejected` events from the pipeline bus's buffered history,\n * narrowed to the lookback window. Returns `[]` if the bus is empty or every\n * event predates the window. Fail-soft: never throws into the review run.\n *\n * The bus is a per-process module singleton (event-bus.ts), so this only sees\n * rejections emitted by `consensus_vote` *in the same process* — i.e. a\n * long-lived MCP server where both tools share the buffer. In separate\n * CLI invocations the buffer starts empty and this correctly yields no signals\n * (the loop degrades to \"no consensus data\" rather than misreporting).\n */\nfunction readBufferedVoteRejections(\n now: number,\n lookbackDays: number\n): readonly VoteRejectedSignalEvent[] {\n const cutoff = now - lookbackDays * DAY_MS;\n return getPipelineEventBus()\n .query({ type: 'signal.vote_rejected' })\n .filter((e): e is VoteRejectedSignalEvent => e.type === 'signal.vote_rejected')\n .filter((e) => e.timestamp >= cutoff);\n}\n\n/**\n * Context-free runner exposed for both the MCP handler and the\n * `nexus-agents improvement-review` CLI subcommand (#2444). Pure dependencies\n * — pass a logger and an OutcomeStore-query result if you want to inject test\n * data; defaults read the global store and a no-op logger.\n */\n/**\n * A measured benchmark suite paired with its STATIC, configured baseline map\n * (#3692/#3246). Injected — there is no global benchmark store and the baseline\n * is never auto-derived from recent runs (that would be the deferred #3230\n * adaptive control). When absent, the perf-regression detector does not run.\n */\nexport interface PerfRegressionInput {\n readonly result: BenchmarkSuiteResult;\n /** Static, configured baselines keyed by `\"<component>::<operation>\"`. */\n readonly baselines: PerfBaselineMap;\n /** Optional override of the default 20% tolerance. */\n readonly toleranceFraction?: number;\n}\n\n/**\n * Gather deterministic perf-regression signals when a benchmark+baseline is\n * injected; otherwise none. Thin wrapper around {@link detectPerfRegressionSignals}\n * so the review runner stays under the per-function line cap.\n */\nfunction gatherPerfRegressionSignals(\n perf: PerfRegressionInput | undefined\n): readonly ImprovementSignal[] {\n if (perf === undefined) return [];\n return detectPerfRegressionSignals(perf.result, perf.baselines, perf.toleranceFraction);\n}\n\nexport async function runImprovementReview(\n input: ImprovementReviewInput,\n deps: {\n readonly logger?: ReturnType<typeof createLogger>;\n /**\n * Optional benchmark measurement + STATIC baseline for the deterministic\n * perf-regression detector (#3692/#3246). Surfaced-only — emitting a signal\n * never mutates a fitness/governance score. Absent → detector is a no-op.\n */\n readonly perfRegression?: PerfRegressionInput;\n } = {}\n): Promise<ImprovementReviewResponse> {\n const logger = deps.logger ?? createLogger({ component: 'improvement_review' });\n const { lookbackDays, fileIssues, minSampleSize, fitnessFloor, selfEvalReportPath } = input;\n const now = Date.now();\n const windowLabel = `${String(lookbackDays)}d`;\n\n const allOutcomes = getOutcomeStore().query();\n const windowed = filterByLookback(allOutcomes, lookbackDays, now);\n const audit = safeFitnessAudit(now, { logger } as HandlerContext);\n\n // Surface high-confidence unanimous self-eval findings as tech-debt signals\n // (#3224) — opt-in via selfEvalReportPath, fail-soft (no path / bad file → none).\n const selfEvalSignals =\n selfEvalReportPath !== undefined\n ? await loadSelfEvalSignals(selfEvalReportPath, windowLabel, logger)\n : [];\n\n // Recurring consensus-rejection patterns (#3259). `consensus_vote` buffers a\n // `signal.vote_rejected` event per rejected plan on the pipeline bus; read the\n // buffered history (not a live subscription — this is a one-shot tool) and\n // window-filter by event timestamp before aggregating.\n const rejectionEvents = readBufferedVoteRejections(now, lookbackDays);\n\n // Tool-fitness deprecation + consolidation CANDIDATES from the #3851 ledger\n // (#3852, closes #3692). SUGGEST-TIER ONLY — never autonomous removal (Epic F).\n // Fail-soft: a ledger read error yields no signals (telemetry must not break\n // the review). Workspace-scoped to defeat context-poisoning (#3852 concern 1).\n const toolFitnessSignals = loadToolFitnessSignals(windowLabel);\n\n // Deterministic perf-regression candidates (#3692/#3246): a measured benchmark\n // vs a STATIC, configured baseline + fixed tolerance. SURFACED-ONLY — appended\n // to the signals list exactly like every other detector; nothing mutates a\n // fitness/governance score or auto-applies a remediation. Runs only when a\n // benchmark+baseline is injected (no global store; no rolling baseline → out of\n // the deferred #3230 adaptive-control scope).\n const perfRegressionSignals = gatherPerfRegressionSignals(deps.perfRegression);\n\n const signals: ImprovementSignal[] = [\n ...detectCliPerformanceFloor(windowed, minSampleSize, windowLabel),\n ...detectFailureCategoryConcentration(windowed, windowLabel),\n ...detectFitnessSignals(audit, fitnessFloor),\n ...detectConsensusRejectionSignals(rejectionEvents, windowLabel),\n ...selfEvalSignals,\n ...toolFitnessSignals,\n ...perfRegressionSignals,\n ];\n signals.sort((a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity]);\n\n // Close the self-tuning loop: a below-floor fitness audit emits\n // signal.fitness_declined onto the typed pipeline bus for the shadow\n // TuneStage (#3147; #3289 Option 2 — observability signals route through bus A).\n emitFitnessDeclinedSignal(audit, fitnessFloor, getPipelineEventBus(), logger);\n\n // Shadow-mode auto-remediation selector (#3540 inc.2a / #3611): record the\n // would-auto-remediate decision per signal. Logs only — executes nothing.\n shadowRecordRemediations(signals, logger);\n\n const { issuesFiled, issuesSkipped } = fileIssues\n ? await fileSignalsAsIssues(signals, { logger } as HandlerContext)\n : { issuesFiled: [], issuesSkipped: [] };\n\n return {\n window: windowLabel,\n totalOutcomes: windowed.length,\n signals,\n // #3540 increment 1: surface remediation tasks derived from the signals\n // (suggest-only — composes existing detection, no auto-invocation).\n remediationTasks: improvementSignalsToTasks(signals),\n issuesFiled,\n issuesSkipped,\n };\n}\n\n/**\n * Best-effort shadow logging of would-auto-remediate decisions (#3611). Never\n * throws — observability must not break the review tool.\n */\nfunction shadowRecordRemediations(signals: readonly ImprovementSignal[], logger: ILogger): void {\n try {\n const shadow = recordRemediationShadow(signals);\n if (shadow.length === 0) return;\n const wouldRemediate = shadow.filter((r) => r.wouldAutoRemediate).length;\n logger.info('Auto-remediation shadow recorded (#3611 — nothing executed)', {\n signals: shadow.length,\n wouldAutoRemediate: wouldRemediate,\n humanGated: shadow.length - wouldRemediate,\n });\n } catch (err) {\n logger.warn('Auto-remediation shadow logging failed (non-fatal)', {\n error: getErrorMessage(err),\n });\n }\n}\n\nasync function reviewHandler(args: unknown, ctx: HandlerContext): Promise<ToolResult> {\n const parsed = ImprovementReviewInputSchema.safeParse(args);\n if (!parsed.success) {\n return toolStructuredError({\n errorCategory: 'validation',\n message: `Validation error: ${formatZodError(parsed.error)}`,\n });\n }\n const response = await runImprovementReview(parsed.data, { logger: ctx.logger });\n return toolSuccessStructured(response as unknown as Record<string, unknown>);\n}\n\n// ============================================================================\n// Registration\n// ============================================================================\n\nexport type ImprovementReviewDeps = BaseMcpToolDeps;\n\nconst description =\n 'Periodic threshold-gated observability-driven improvement loop. Reads OutcomeStore + ' +\n 'fitness audit, surfaces patterns crossing documented thresholds as candidate findings. ' +\n 'When fileIssues=true, files candidate GitHub issues via `gh issue create` (rate-limited ' +\n 'to 5 per run, deduped against open issues). Never auto-merges. Replaces the deleted ' +\n 'self-development engine (#2402).';\n\nconst TOOL_INPUT_SCHEMA = {\n lookbackDays: z\n .number()\n .int()\n .min(1)\n .max(90)\n .optional()\n .describe('Lookback window for outcome data, in days. Default 7.'),\n fileIssues: z\n .boolean()\n .optional()\n .describe(\n 'When true, file candidate issues for crossed thresholds (default false — return signals only)'\n ),\n minSampleSize: z\n .number()\n .int()\n .min(1)\n .max(1000)\n .optional()\n .describe('Minimum sample size before a CLI/category signal fires (default 5).'),\n fitnessFloor: z\n .number()\n .int()\n .min(0)\n .max(100)\n .optional()\n .describe('Fitness score below this threshold triggers a tech-debt signal (default 90).'),\n selfEvalReportPath: z\n .string()\n .optional()\n .describe(\n 'Optional path to a self-eval JSON report. High-confidence unanimous ' +\n 'deprecate/refactor findings surface as tech-debt signals (#3224).'\n ),\n};\n\n/** @category MCP */\nexport function registerImprovementReviewTool(\n server: McpServer,\n deps: ImprovementReviewDeps\n): void {\n const logger = deps.logger ?? createLogger({ tool: 'improvement_review' });\n const secureHandler = createSecureHandler(reviewHandler, {\n toolName: 'improvement_review',\n rateLimiter: deps.rateLimiter,\n logger,\n });\n const guardedHandler = withPrerequisite('improvement_review', secureHandler);\n const timeoutMs = getToolTimeout('improvement_review', deps.security);\n const wrappedHandler = wrapToolWithTimeout('improvement_review', guardedHandler, {\n timeoutMs,\n logger,\n });\n server.registerTool(\n 'improvement_review',\n {\n description,\n inputSchema: TOOL_INPUT_SCHEMA,\n annotations: getToolAnnotations('improvement_review'),\n },\n toSdkCallback(wrappedHandler)\n );\n logger.info('Registered improvement_review tool');\n}\n","/**\n * nexus-agents/mcp - Tool Prerequisite Gates\n *\n * Blocks sensitive MCP tools from running unless a **world-state\n * precondition** holds at call time (Issue #2652, Epic B).\n *\n * DESIGN — predicate, not session-ordering. A prerequisite is a predicate\n * over observable world state (is `gh` installed? is the data dir\n * writable?), evaluated on every invocation. It is NOT \"tool A must have\n * been called before tool B\" — MCP `tools/call` invocations are\n * independent, and a session-ordering gate is satisfied by an LLM calling\n * the prior tool pointlessly without making the precondition true. If a\n * requirement can only be expressed as \"call X first,\" it is not a\n * prerequisite — it is the tool's own internal responsibility (e.g.\n * untrusted-input trust-tier classification stays inside `issue_triage`\n * per `.rules/untrusted-input.md`, it is not gated here).\n *\n * Fail-closed: a predicate that throws blocks the tool.\n *\n * @module mcp/middleware/tool-prerequisites\n * @see Issue #2652\n */\n\nimport { execFile } from 'node:child_process';\nimport { access, constants } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { promisify } from 'node:util';\nimport { getErrorMessage } from '../../core/index.js';\nimport { getNexusDataDir } from '../../config/nexus-data-dir.js';\nimport { toolStructuredError, type ToolResult } from '../tools/tool-result.js';\nimport type { ContextAwareToolHandler, ToolHandler } from './middleware-chain.js';\n\nconst execFileAsync = promisify(execFile);\n\n/** Outcome of evaluating a prerequisite predicate. */\nexport interface PrerequisiteResult {\n ok: boolean;\n /** When `!ok`: what would make the predicate pass. Surfaced to the caller. */\n remediation?: string;\n}\n\n/** A world-state precondition a guarded tool requires at call time. */\nexport interface ToolPrerequisite {\n /** Stable identifier, e.g. `data-dir-writable`. */\n name: string;\n /** Why the tool needs it — for `.rules/tool-prerequisites.md` + the block envelope. */\n rationale: string;\n /** World-state predicate. MUST be cheap and side-effect-free. */\n check: () => Promise<PrerequisiteResult> | PrerequisiteResult;\n}\n\n// ============================================================================\n// Predicates\n// ============================================================================\n\n/** The `gh` CLI is on PATH — required by tools that file/read GitHub state. */\nasync function ghCliAvailable(): Promise<PrerequisiteResult> {\n try {\n await execFileAsync('gh', ['--version'], { timeout: 5000 });\n return { ok: true };\n } catch (err) {\n return {\n ok: false,\n remediation: `the 'gh' CLI is not available (${getErrorMessage(err)}) — install GitHub CLI and authenticate (\\`gh auth login\\`)`,\n };\n }\n}\n\n/**\n * The runtime data directory is writable, or — if it does not exist yet —\n * creatable (its parent is writable). Memory/registry backends create the\n * dir on demand, so \"not yet created\" is not a failure; an unwritable\n * parent is.\n */\nasync function dataDirWritable(): Promise<PrerequisiteResult> {\n const dir = getNexusDataDir();\n try {\n await access(dir, constants.W_OK);\n return { ok: true };\n } catch {\n // Dir may not exist yet — backends create it on demand. Treat a\n // writable parent (creatable) as satisfying the precondition.\n try {\n await access(dirname(dir), constants.W_OK);\n return { ok: true };\n } catch (err) {\n return {\n ok: false,\n remediation: `NEXUS_DATA_DIR (${dir}) is not writable or creatable (${getErrorMessage(err)}) — fix its permissions; run \\`nexus-agents doctor\\` to diagnose`,\n };\n }\n }\n}\n\n// ============================================================================\n// Registry\n// ============================================================================\n\n/**\n * Tools guarded by a call-time prerequisite. Keep this in sync with\n * `.rules/tool-prerequisites.md` — the `check:tool-prerequisites` CI gate\n * verifies every non-read-only tool is either listed here or in\n * `NO_PREREQUISITE` with a reason.\n */\nexport const TOOL_PREREQUISITES: Record<string, ToolPrerequisite> = {\n improvement_review: {\n name: 'gh-cli-available',\n rationale:\n \"improvement_review's fileIssues mode shells out to `gh` to file candidate issues; without it the write path fails mid-operation\",\n check: ghCliAvailable,\n },\n memory_write: {\n name: 'data-dir-writable',\n rationale:\n 'memory_write persists entries under NEXUS_DATA_DIR — an unwritable data dir fails the write confusingly mid-operation',\n check: dataDirWritable,\n },\n registry_import: {\n name: 'data-dir-writable',\n rationale:\n 'registry_import persists a draft registry entry under NEXUS_DATA_DIR when not in dryRun mode',\n check: dataDirWritable,\n },\n};\n\n/**\n * Non-read-only tools that deliberately have NO call-time prerequisite,\n * with the reason. The `check:tool-prerequisites` gate requires every\n * non-read-only tool to appear here or in `TOOL_PREREQUISITES`, so a newly\n * added sensitive tool can't ship ungated by omission.\n */\nexport const NO_PREREQUISITE: Record<string, string> = {\n delegate_to_model:\n 'inspects a task and recommends a model + records the decision to tool-memory; no world-state precondition to gate',\n orchestrate: 'orchestration is self-contained; sub-tool calls carry their own gates',\n create_expert: 'in-memory expert creation; no external precondition',\n execute_expert:\n 'adapter availability is handled by the resilient-adapter circuit breaker, not a pre-gate',\n run_workflow: 'workflow execution is self-contained; step tools carry their own gates',\n run_graph_workflow: 'graph execution is self-contained; node tools carry their own gates',\n run_pipeline: 'pipeline execution is self-contained; stage tools carry their own gates',\n run_dev_pipeline: 'pipeline execution is self-contained; stage tools carry their own gates',\n execute_spec: 'spec execution is self-contained; stage tools carry their own gates',\n consensus_vote: 'voter-CLI availability is handled by per-voter fallback, not a pre-gate',\n ci_health_check:\n 'reads upstream CI status + appends a telemetry event (#3530); no world-state precondition to gate',\n supply_chain_tradeoff_panel: 'wraps consensus_vote; same per-voter fallback applies',\n pr_review: 'wraps consensus_vote; same per-voter fallback applies',\n research_add:\n 'arXiv fetch failures surface as a transient envelope from the handler; no useful pre-gate',\n research_add_source:\n 'quality_score is computed from caller-provided quality_signals only (no GitHub fetch); no useful pre-gate',\n research_catalog_review: 'operates on local catalog state already loaded by the handler',\n issue_triage:\n 'untrusted-input safety (trust-tier classification, Rule of Two) is internal-handler logic per .rules/untrusted-input.md — not a call-time world-state predicate',\n cancel_job:\n 'reads + writes the local sidecar file only; cancel-after-complete is an idempotent no-op (first-wins) so misuse is bounded — no pre-gate needed',\n run_quality_gate:\n 'stateless QA gate over the given projectDir; a missing toolchain (tsc/eslint/vitest/build) surfaces as a check failure in the verdict, not a call-time world-state precondition — no pre-gate needed',\n};\n\n// ============================================================================\n// Middleware\n// ============================================================================\n\n/** Either MCP handler shape, both structurally callable with `(args, ctx?)`. */\ntype AnyToolHandler = ContextAwareToolHandler | ToolHandler;\n/** Concrete callable accepting an optional context — what the gate produces. */\ntype GuardedHandler = (args: unknown, ctx?: unknown) => Promise<ToolResult>;\n\n/**\n * Wrap `handler` so `prereq` is evaluated before it runs. A failing or\n * throwing predicate returns a structured `permission` error envelope\n * (#2649) carrying the failed prerequisite + a remediation hint in\n * `detail` — so the caller knows how to recover, not just that it was\n * blocked. Exported for testing; production code uses `withPrerequisite`.\n */\nexport function applyPrerequisite(\n toolName: string,\n prereq: ToolPrerequisite,\n handler: AnyToolHandler\n): GuardedHandler {\n return async (args: unknown, ctx?: unknown): Promise<ToolResult> => {\n let result: PrerequisiteResult;\n try {\n result = await prereq.check();\n } catch (err) {\n // Fail closed — a predicate that throws blocks the tool.\n result = { ok: false, remediation: `prerequisite check threw: ${getErrorMessage(err)}` };\n }\n if (!result.ok) {\n return toolStructuredError({\n errorCategory: 'permission',\n message: `${toolName} blocked: prerequisite '${prereq.name}' not satisfied`,\n detail: {\n failedPrerequisite: prereq.name,\n rationale: prereq.rationale,\n remediation: result.remediation ?? 'see .rules/tool-prerequisites.md',\n },\n });\n }\n return (handler as GuardedHandler)(args, ctx);\n };\n}\n\n/**\n * Wrap a handler so its tool's prerequisite (if any) is evaluated before\n * the handler runs. Tools with no entry in `TOOL_PREREQUISITES` pass\n * through untouched.\n */\nexport function withPrerequisite(toolName: string, handler: AnyToolHandler): AnyToolHandler {\n const prereq = TOOL_PREREQUISITES[toolName];\n if (prereq === undefined) return handler;\n return applyPrerequisite(toolName, prereq, handler);\n}\n","/**\n * CLI Orchestration Fitness Score — real filesystem analysis.\n * Penalizes duplicate paths, hidden behavior, non-determinism, poor\n * observability, config sprawl, cross-layer coupling. Rewards canonical\n * paths, determinism, telemetry, CLI ergonomics, governance.\n * @module governance/fitness-score\n */\n\n/* eslint-disable max-lines -- cohesive fitness calculator (governance allows 400-600) */\n\nimport { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createLogger, type ILogger } from '../core/index.js';\n\n/** Find package root by walking up from current dir to find package.json with our name */\nfunction findPkgRoot(): string {\n let dir = import.meta.dirname;\n for (let i = 0; i < 10; i++) {\n const pkgPath = join(dir, 'package.json');\n if (existsSync(pkgPath)) {\n const content = readFileSync(pkgPath, 'utf-8');\n if (content.includes('\"nexus-agents\"')) return dir;\n }\n dir = join(dir, '..');\n }\n return join(import.meta.dirname, '../..');\n}\n\nconst PKG_ROOT = findPkgRoot();\nconst SRC_ROOT = join(PKG_ROOT, 'src');\nconst REPO_ROOT = join(PKG_ROOT, '../..');\nconst DOCS_ROOT = join(REPO_ROOT, 'docs');\n\nconst DETERMINISM_EXCLUDES: RegExp[] = [\n /\\.test\\.ts$/,\n /\\.spec\\.ts$/,\n /random-provider\\.ts$/,\n /time-provider\\.ts$/,\n];\n\n// =========================================================================\n// Filesystem utility methods (inlined from scripts/fitness-utils.ts)\n// =========================================================================\n\nfunction countFiles(dir: string, pattern: RegExp): number {\n if (!existsSync(dir)) return 0;\n let count = 0;\n for (const entry of readdirSync(dir)) {\n const fullPath = join(dir, entry);\n const stat = statSync(fullPath);\n if (stat.isDirectory() && !entry.startsWith('.')) {\n count += countFiles(fullPath, pattern);\n } else if (pattern.test(entry)) {\n count++;\n }\n }\n return count;\n}\n\nfunction fileContains(filePath: string, pattern: RegExp): boolean {\n if (!existsSync(filePath)) return false;\n return pattern.test(readFileSync(filePath, 'utf-8'));\n}\n\nfunction isExcluded(entry: string, excludePatterns?: RegExp[]): boolean {\n return excludePatterns?.some((p) => p.test(entry)) ?? false;\n}\n\nfunction countMatchesInFile(fullPath: string, contentPattern: RegExp): number {\n const matches = readFileSync(fullPath, 'utf-8').match(contentPattern);\n return matches?.length ?? 0;\n}\n\nfunction countPatternInDir(\n dir: string,\n filePattern: RegExp,\n contentPattern: RegExp,\n excludePatterns?: RegExp[]\n): number {\n if (!existsSync(dir)) return 0;\n let count = 0;\n for (const entry of readdirSync(dir)) {\n const fullPath = join(dir, entry);\n const stat = statSync(fullPath);\n if (stat.isDirectory() && !entry.startsWith('.') && entry !== 'node_modules') {\n count += countPatternInDir(fullPath, filePattern, contentPattern, excludePatterns);\n } else if (filePattern.test(entry) && !isExcluded(entry, excludePatterns)) {\n count += countMatchesInFile(fullPath, contentPattern);\n }\n }\n return count;\n}\n\n// =========================================================================\n// Public types\n// =========================================================================\n\n/**\n * Individual fitness dimension scores.\n */\nexport interface FitnessDimensions {\n /** Penalty: duplicate paths to same workflow (0-20, higher = better) */\n readonly canonicalPaths: number;\n /** Penalty: hidden/magic behavior (0-15, higher = better) */\n readonly explicitBehavior: number;\n /** Reward: deterministic execution (0-15, higher = better) */\n readonly determinism: number;\n /** Reward: observability coverage (0-15, higher = better) */\n readonly observability: number;\n /** Penalty: config surface area (0-10, higher = better) */\n readonly configSimplicity: number;\n /** Penalty: cross-layer coupling (0-10, higher = better) */\n readonly layerSeparation: number;\n /** Reward: CLI ergonomics (0-10, higher = better) */\n readonly operatorErgonomics: number;\n /** Reward: governance injection (0-5, higher = better) */\n readonly governanceIntegration: number;\n}\n\n/**\n * The closed set of known fitness dimensions. Use this (not a free string) when\n * validating a dimension carried in untrusted/serialized data — e.g. a finding's\n * `dimension` flowing into a signal payload (#3227, findings-as-data).\n */\nexport type FitnessDimension = keyof FitnessDimensions;\n\n/**\n * Maximum points each dimension can score — the SINGLE SOURCE OF TRUTH for\n * per-dimension maxima (#3227). {@link FitnessScoreCalculator.registerDefaultChecks}\n * registers each check with `FITNESS_DIMENSION_MAX[dimension]` so the registered\n * `maxPoints` can never silently drift from this table, and downstream consumers\n * (e.g. the per-dimension fitness-remediation signal) compute a below-target\n * threshold as a fraction of the dimension's OWN max rather than a global floor.\n *\n * The maxima sum to 100 (the `score` range). Mirrors the `0-N` ranges documented\n * on each {@link FitnessDimensions} field.\n */\nexport const FITNESS_DIMENSION_MAX: Readonly<Record<FitnessDimension, number>> = {\n canonicalPaths: 20,\n explicitBehavior: 15,\n determinism: 15,\n observability: 15,\n configSimplicity: 10,\n layerSeparation: 10,\n operatorErgonomics: 10,\n governanceIntegration: 5,\n};\n\n/**\n * Detailed fitness audit result.\n */\nexport interface FitnessAudit {\n /** Overall score (0-100) */\n readonly score: number;\n /** Individual dimension scores */\n readonly dimensions: FitnessDimensions;\n /** Specific findings */\n readonly findings: readonly FitnessFinding[];\n /** Timestamp of audit */\n readonly timestamp: string;\n /** Version/commit reference */\n readonly version: string;\n /**\n * Whether the audit actually ran against the nexus-agents source tree (#3621).\n * `false` is the \"could not audit from here\" sentinel (e.g. run from the global\n * npm install, where the bundled `src/` lacks `cli-adapters/`): the score is a\n * meaningless 0, NOT a real low-fitness result. Consumers (e.g.\n * improvement_review) MUST NOT treat a `false` audit's score as a signal.\n * Absent/`true` → a genuine audit.\n */\n readonly auditable?: boolean;\n}\n\n/**\n * Individual finding from audit.\n */\nexport interface FitnessFinding {\n /** Dimension affected */\n readonly dimension: keyof FitnessDimensions;\n /** Issue severity: 'info' | 'warning' | 'critical' */\n readonly severity: 'info' | 'warning' | 'critical';\n /** Description */\n readonly description: string;\n /** Points deducted */\n readonly pointsDeducted: number;\n /** Location in code (optional) */\n readonly location?: string;\n /** Suggested fix (optional) */\n readonly suggestion?: string;\n}\n\n/**\n * Fitness check definition.\n */\ninterface FitnessCheck {\n readonly dimension: keyof FitnessDimensions;\n readonly maxPoints: number;\n readonly name: string;\n readonly check: () => FitnessCheckResult;\n}\n\n/**\n * Result of a single fitness check.\n */\ninterface FitnessCheckResult {\n readonly score: number;\n readonly findings: FitnessFinding[];\n}\n\n/** Clamp score to [0, max]. */\nfunction clamp(score: number, max: number): number {\n return Math.max(0, Math.min(max, score));\n}\n\n/**\n * CLI Orchestration Fitness Score calculator.\n */\nexport class FitnessScoreCalculator {\n private readonly logger: ILogger;\n private readonly checks: FitnessCheck[] = [];\n\n constructor(logger?: ILogger) {\n this.logger = logger ?? createLogger({ component: 'FitnessScoreCalculator' });\n this.registerDefaultChecks();\n }\n\n /** Register default fitness checks. */\n private registerDefaultChecks(): void {\n // maxPoints is sourced from FITNESS_DIMENSION_MAX (the single source of truth,\n // #3227) so a registered check's max can never drift from the published table.\n const reg = (\n dimension: keyof FitnessDimensions,\n name: string,\n check: () => FitnessCheckResult\n ): void => {\n this.checks.push({ dimension, maxPoints: FITNESS_DIMENSION_MAX[dimension], name, check });\n };\n reg('canonicalPaths', 'Canonical Paths', () => this.checkCanonicalPaths());\n reg('explicitBehavior', 'Explicit Behavior', () => this.checkExplicitBehavior());\n reg('determinism', 'Determinism', () => this.checkDeterminism());\n reg('observability', 'Observability', () => this.checkObservability());\n reg('configSimplicity', 'Config Simplicity', () => this.checkConfigSimplicity());\n reg('layerSeparation', 'Layer Separation', () => this.checkLayerSeparation());\n reg('operatorErgonomics', 'Operator Ergonomics', () => this.checkOperatorErgonomics());\n reg('governanceIntegration', 'Governance Integration', () =>\n this.checkGovernanceIntegration()\n );\n }\n\n /** Run full fitness audit. */\n audit(version: string): FitnessAudit {\n const findings: FitnessFinding[] = [];\n const dimensions: Record<string, number> = {};\n\n // #2716 — the audit's existsSync checks look at SRC_ROOT-relative paths\n // (cli-adapters/composite-router.ts, cli/doctor.ts, etc). When run from\n // an `npm install -g nexus-agents` copy, SRC_ROOT points at the installed\n // package's `src/` which only contains workflow templates — not the full\n // source tree. Result: every existsSync returns false and the audit\n // emits a parade of fictional \"missing\" findings against a healthy\n // source tree. (`npx nexus-agents fitness-audit` from a repo root hits\n // this path because npx resolves to the GLOBAL bin, not the local\n // workspace bundle.) Bail with a clear single-finding result instead.\n const cliAdaptersDir = join(SRC_ROOT, 'cli-adapters');\n if (!existsSync(cliAdaptersDir)) {\n return this.notSourceRepoResult(version);\n }\n\n for (const check of this.checks) {\n this.logger.debug(`Running fitness check: ${check.name}`);\n const result = check.check();\n dimensions[check.dimension] = result.score;\n findings.push(...result.findings);\n }\n\n const score = Object.values(dimensions).reduce((sum, val) => sum + val, 0);\n this.logger.info('Fitness audit complete', { score, version });\n\n // Build a strictly-typed FitnessDimensions instead of `as unknown as` cast\n // (#1913 Class G). If a check skipped a dimension it defaults to 0,\n // making it explicit rather than UB.\n const safeDim = (k: keyof FitnessDimensions): number => dimensions[k] ?? 0;\n const typedDimensions: FitnessDimensions = {\n canonicalPaths: safeDim('canonicalPaths'),\n explicitBehavior: safeDim('explicitBehavior'),\n determinism: safeDim('determinism'),\n observability: safeDim('observability'),\n configSimplicity: safeDim('configSimplicity'),\n layerSeparation: safeDim('layerSeparation'),\n operatorErgonomics: safeDim('operatorErgonomics'),\n governanceIntegration: safeDim('governanceIntegration'),\n };\n\n return {\n score,\n dimensions: typedDimensions,\n findings,\n timestamp: new Date().toISOString(),\n version,\n auditable: true,\n };\n }\n\n /**\n * Return when the runtime SRC_ROOT doesn't look like the nexus-agents\n * source tree (#2716). One finding, score 0 — distinct from \"the source\n * tree is broken\" because every existsSync would falsely report missing.\n */\n private notSourceRepoResult(version: string): FitnessAudit {\n const finding: FitnessFinding = {\n dimension: 'governanceIntegration',\n severity: 'info',\n description:\n 'fitness-audit must run against the nexus-agents source repo, ' +\n `but ${SRC_ROOT}/cli-adapters does not exist. You are likely ` +\n 'running the installed npm package via `npx nexus-agents`, which ' +\n 'ships only the bundled dist/. Clone the source repo and run ' +\n '`node packages/nexus-agents/dist/cli.js fitness-audit` (or invoke ' +\n '`pnpm fitness-audit` from the workspace root).',\n pointsDeducted: 0,\n };\n return {\n score: 0,\n dimensions: {\n canonicalPaths: 0,\n explicitBehavior: 0,\n determinism: 0,\n observability: 0,\n configSimplicity: 0,\n layerSeparation: 0,\n operatorErgonomics: 0,\n governanceIntegration: 0,\n },\n findings: [finding],\n timestamp: new Date().toISOString(),\n version,\n auditable: false,\n };\n }\n\n // =========================================================================\n // Individual Checks — real filesystem analysis\n // =========================================================================\n\n /**\n * Check canonical paths: penalize duplicate router implementations.\n *\n * The current minimum is 6 (raised from 5 in #2063 after an audit):\n * 1. composite-router — pipeline orchestrator\n * 2. budget-router — budget/cost filtering\n * 3. zero-router — hard-constraint exclusion\n * 4. preference-router — user/task preference application\n * 5. topsis-router — TOPSIS multi-criteria scoring\n * 6. agreement-cascade-router — agreement-based cascade retry\n *\n * Each stage is distinct per CLAUDE.md's documented pipeline:\n * Task → BudgetRouter → ZeroRouter → PreferenceRouter → TopsisRouter → Agreement → Model\n */\n private checkCanonicalPaths(): FitnessCheckResult {\n const findings: FitnessFinding[] = [];\n let score = 20;\n\n const routerCount = countFiles(join(SRC_ROOT, 'cli-adapters'), /router\\.ts$/);\n const ROUTER_COUNT_THRESHOLD = 6;\n if (routerCount > ROUTER_COUNT_THRESHOLD) {\n const excess = routerCount - ROUTER_COUNT_THRESHOLD;\n const deduction = Math.min(5, excess);\n score -= deduction;\n findings.push(\n this.finding(\n 'canonicalPaths',\n 'warning',\n `${String(routerCount)} router implementations found (target: <=${String(ROUTER_COUNT_THRESHOLD)})`,\n deduction,\n 'Consolidate duplicate routers into CompositeRouter'\n )\n );\n }\n\n if (existsSync(join(SRC_ROOT, 'cli-adapters/composite-router.ts'))) {\n score += 2;\n } else {\n score -= 3;\n findings.push(\n this.finding(\n 'canonicalPaths',\n 'critical',\n 'CompositeRouter missing — no unified routing entry point',\n 3\n )\n );\n }\n\n score = this.checkOrchestratorInterface(score, findings);\n\n return { score: clamp(score, 20), findings };\n }\n\n /** Sub-check for IOrchestrator interface and adapter wiring. */\n private checkOrchestratorInterface(score: number, findings: FitnessFinding[]): number {\n const orchPath = join(SRC_ROOT, 'core/types/orchestrator.ts');\n if (existsSync(orchPath) && fileContains(orchPath, /interface IOrchestrator/)) {\n score += 3;\n } else {\n score -= 2;\n findings.push(\n this.finding('canonicalPaths', 'warning', 'No IOrchestrator interface in core/types', 2)\n );\n }\n\n const adapterPath = join(SRC_ROOT, 'orchestration/orchestrator-adapters.ts');\n if (existsSync(adapterPath) && fileContains(adapterPath, /TechLeadAdapter|PuppeteerAdapter/)) {\n score += 2;\n }\n\n return score;\n }\n\n /**\n * Check explicit behavior: penalize hidden/magic behavior.\n *\n * Implementation is intentionally filesystem-signal-based (no AST parse).\n * The `NEXUS_ALLOW_MOCK_ORCHESTRATION` guard and magic-routing pattern\n * grep capture the observable failure modes that historically slipped\n * past review. AST-based detection of implicit fallbacks was considered\n * but not pursued — it would significantly widen this function's\n * footprint and the filesystem signals already catch the recurring\n * regressions. Revisit only if a new class of hidden-behavior bug\n * surfaces that this grep-over-source approach can't catch.\n */\n private checkExplicitBehavior(): FitnessCheckResult {\n const findings: FitnessFinding[] = [];\n let score = 15;\n\n // Check: mock orchestration requires explicit env var opt-in\n const mockGuardCount = countPatternInDir(\n SRC_ROOT,\n /\\.ts$/,\n /NEXUS_ALLOW_MOCK_ORCHESTRATION/g,\n DETERMINISM_EXCLUDES\n );\n if (mockGuardCount === 0) {\n score -= 3;\n findings.push(\n this.finding(\n 'explicitBehavior',\n 'warning',\n 'No NEXUS_ALLOW_MOCK_ORCHESTRATION guard found — mock fallback may be implicit',\n 3,\n 'Require explicit env var for mock orchestration'\n )\n );\n }\n\n // Check: magic routing patterns (delegate without explicit capability match)\n const magicRouting = countPatternInDir(\n SRC_ROOT,\n /\\.ts$/,\n /fallback.*=.*true|implicitRoute/g,\n DETERMINISM_EXCLUDES\n );\n if (magicRouting > 5) {\n const deduction = Math.min(3, Math.floor(magicRouting / 3));\n score -= deduction;\n findings.push(\n this.finding(\n 'explicitBehavior',\n 'info',\n `${String(magicRouting)} implicit fallback/routing patterns detected`,\n deduction\n )\n );\n }\n\n return { score: clamp(score, 15), findings };\n }\n\n /** Check determinism: penalize unseeded random and raw Date.now(). */\n private checkDeterminism(): FitnessCheckResult {\n const findings: FitnessFinding[] = [];\n let score = 15;\n\n score = this.checkRandomDeterminism(score, findings);\n score = this.checkTimeDeterminism(score, findings);\n\n return { score: clamp(score, 15), findings };\n }\n\n /** Sub-check for Math.random() and injectable random provider. */\n private checkRandomDeterminism(score: number, findings: FitnessFinding[]): number {\n const randomCount = countPatternInDir(\n SRC_ROOT,\n /\\.ts$/,\n /Math\\.random\\(\\)/g,\n DETERMINISM_EXCLUDES\n );\n if (randomCount > 10) {\n const deduction = Math.min(5, Math.floor(randomCount / 5));\n score -= deduction;\n findings.push(\n this.finding(\n 'determinism',\n 'warning',\n `${String(randomCount)} unseeded Math.random() calls in production code`,\n deduction,\n 'Use getRandomProvider() for injectable randomness'\n )\n );\n } else if (randomCount === 0) {\n score += 2;\n }\n\n if (existsSync(join(SRC_ROOT, 'core/random-provider.ts'))) {\n score += 1;\n }\n const randomUsage = countPatternInDir(\n SRC_ROOT,\n /\\.ts$/,\n /getRandomProvider\\(\\)/g,\n DETERMINISM_EXCLUDES\n );\n if (randomUsage > 5) {\n score += 1;\n }\n\n return score;\n }\n\n /** Sub-check for Date.now() and injectable time provider. */\n private checkTimeDeterminism(score: number, findings: FitnessFinding[]): number {\n const dateNowCount = countPatternInDir(\n SRC_ROOT,\n /\\.ts$/,\n /Date\\.now\\(\\)/g,\n DETERMINISM_EXCLUDES\n );\n if (dateNowCount > 50) {\n score -= 2;\n findings.push(\n this.finding(\n 'determinism',\n 'info',\n `${String(dateNowCount)} Date.now() calls in production code`,\n 2,\n 'Use getTimeProvider() for injectable time'\n )\n );\n }\n\n if (existsSync(join(SRC_ROOT, 'core/time-provider.ts'))) {\n score += 1;\n }\n const timeUsage = countPatternInDir(\n SRC_ROOT,\n /\\.ts$/,\n /getTimeProvider\\(\\)/g,\n DETERMINISM_EXCLUDES\n );\n if (timeUsage > 10) {\n score += 1;\n }\n\n return score;\n }\n\n /** Check observability: reward tracing, logging, and audit coverage. */\n private checkObservability(): FitnessCheckResult {\n const findings: FitnessFinding[] = [];\n let score = 15;\n\n if (existsSync(join(SRC_ROOT, 'observability/swarm-observer.ts'))) {\n score += 3;\n } else {\n score -= 3;\n findings.push(\n this.finding(\n 'observability',\n 'warning',\n 'No SwarmObserver found',\n 3,\n 'Add observability/swarm-observer.ts'\n )\n );\n }\n\n if (existsSync(join(SRC_ROOT, 'core/trace.ts'))) {\n score += 2;\n }\n\n const loggerCount = countPatternInDir(SRC_ROOT, /\\.ts$/, /createLogger\\(/g);\n if (loggerCount > 50) {\n score += 2;\n } else {\n findings.push(\n this.finding(\n 'observability',\n 'info',\n `Only ${String(loggerCount)} createLogger() calls (target: >50)`,\n 0\n )\n );\n }\n\n if (existsSync(join(SRC_ROOT, 'audit'))) {\n score += 2;\n }\n\n return { score: clamp(score, 15), findings };\n }\n\n /** Check config simplicity: penalize excessive schema sprawl. */\n private checkConfigSimplicity(): FitnessCheckResult {\n const findings: FitnessFinding[] = [];\n let score = 10;\n\n const schemaCount = countFiles(join(SRC_ROOT, 'config'), /schema.*\\.ts$/);\n if (schemaCount > 10) {\n score -= 2;\n findings.push(\n this.finding(\n 'configSimplicity',\n 'info',\n `${String(schemaCount)} config schemas (target: <=10)`,\n 2,\n 'Consolidate related schemas'\n )\n );\n } else {\n score += 1;\n }\n\n if (existsSync(join(SRC_ROOT, 'config/config-loader.ts'))) {\n score += 2;\n }\n if (existsSync(join(SRC_ROOT, 'config/config-manager.ts'))) {\n score += 1;\n }\n\n return { score: clamp(score, 10), findings };\n }\n\n /** Check layer separation: penalize cross-layer imports. */\n private checkLayerSeparation(): FitnessCheckResult {\n const findings: FitnessFinding[] = [];\n let score = 10;\n\n const adapterAgentImports = countPatternInDir(\n join(SRC_ROOT, 'adapters'),\n /\\.ts$/,\n /from ['\"]\\.\\.\\/agents\\//g\n );\n if (adapterAgentImports > 0) {\n const deduction = Math.min(5, adapterAgentImports);\n score -= deduction;\n findings.push(\n this.finding(\n 'layerSeparation',\n 'warning',\n `${String(adapterAgentImports)} adapter->agent import violations`,\n deduction,\n 'Adapters should not import from agents layer'\n )\n );\n } else {\n score += 2;\n }\n\n const coreMcpImports = countPatternInDir(\n join(SRC_ROOT, 'core'),\n /\\.ts$/,\n /from ['\"]\\.\\.\\/mcp\\//g\n );\n if (coreMcpImports > 0) {\n const deduction = Math.min(3, coreMcpImports);\n score -= deduction;\n findings.push(\n this.finding(\n 'layerSeparation',\n 'critical',\n `${String(coreMcpImports)} core->MCP import violations`,\n deduction,\n 'Core must not depend on MCP layer'\n )\n );\n } else {\n score += 1;\n }\n\n return { score: clamp(score, 10), findings };\n }\n\n /** Check operator ergonomics: reward rich CLI commands. */\n private checkOperatorErgonomics(): FitnessCheckResult {\n const findings: FitnessFinding[] = [];\n let score = 10;\n\n const commandCount = countFiles(join(SRC_ROOT, 'cli'), /\\.ts$/);\n if (commandCount >= 20) {\n score += 3;\n } else {\n findings.push(\n this.finding(\n 'operatorErgonomics',\n 'info',\n `${String(commandCount)} CLI commands (target: >=20)`,\n 0\n )\n );\n }\n\n score = this.checkCliCommands(score, findings);\n\n return { score: clamp(score, 10), findings };\n }\n\n /** Sub-check for essential CLI commands (doctor, setup, demo, config). */\n private checkCliCommands(score: number, findings: FitnessFinding[]): number {\n const commands: Array<[string, string, number]> = [\n ['cli/doctor.ts', 'Doctor command', 2],\n ['cli/setup-command.ts', 'Setup wizard', 2],\n ['cli/demo-command.ts', 'Demo command', 1],\n ['cli/config-command.ts', 'Config command', 1],\n ];\n\n for (const [path, name, bonus] of commands) {\n if (existsSync(join(SRC_ROOT, path))) {\n score += bonus;\n } else {\n findings.push(this.finding('operatorErgonomics', 'info', `Missing ${name} (${path})`, 0));\n }\n }\n\n return score;\n }\n\n /** Check governance integration: policy firewall, rate limiter, docs. */\n private checkGovernanceIntegration(): FitnessCheckResult {\n const findings: FitnessFinding[] = [];\n let score = 5;\n\n score = this.checkGovernanceDocs(score, findings);\n score = this.checkGovernanceInfra(score, findings);\n\n return { score: clamp(score, 5), findings };\n }\n\n /** Sub-check for governance documentation artifacts. */\n private checkGovernanceDocs(score: number, findings: FitnessFinding[]): number {\n if (!existsSync(join(REPO_ROOT, 'CLAUDE.md'))) {\n score -= 3;\n findings.push(\n this.finding('governanceIntegration', 'critical', 'No CLAUDE.md governance document', 3)\n );\n } else {\n score += 1;\n }\n\n if (existsSync(join(DOCS_ROOT, 'architecture/wiring-graph.json'))) {\n score += 1;\n }\n\n if (existsSync(join(DOCS_ROOT, 'adr'))) {\n score += 1;\n } else {\n findings.push(this.finding('governanceIntegration', 'info', 'No ADR directory', 0));\n }\n\n return score;\n }\n\n /** Sub-check for governance runtime infrastructure. */\n private checkGovernanceInfra(score: number, findings: FitnessFinding[]): number {\n const hasPolicyFirewall =\n countPatternInDir(join(SRC_ROOT, 'security'), /\\.ts$/, /PolicyGate|policyFirewall/g) > 0;\n if (hasPolicyFirewall) {\n score += 1;\n } else {\n findings.push(\n this.finding(\n 'governanceIntegration',\n 'warning',\n 'No policy firewall detected in security layer',\n 0\n )\n );\n }\n\n const hasRateLimiter = countPatternInDir(SRC_ROOT, /\\.ts$/, /RateLimiter|rateLimiter/g) > 0;\n if (hasRateLimiter) {\n score += 1;\n }\n\n return score;\n }\n\n /** Helper to create a FitnessFinding with defaults. */\n private finding(\n dimension: keyof FitnessDimensions,\n severity: FitnessFinding['severity'],\n description: string,\n pointsDeducted: number,\n suggestion?: string\n ): FitnessFinding {\n const base: FitnessFinding = { dimension, severity, description, pointsDeducted };\n if (suggestion !== undefined) {\n return { ...base, suggestion };\n }\n return base;\n }\n}\n\n/**\n * Create a fitness score calculator.\n */\nexport function createFitnessScoreCalculator(logger?: ILogger): FitnessScoreCalculator {\n return new FitnessScoreCalculator(logger);\n}\n\n/**\n * Quick function to get current fitness score.\n */\nexport function calculateFitnessScore(version: string): FitnessAudit {\n const calculator = createFitnessScoreCalculator();\n return calculator.audit(version);\n}\n","/**\n * improvement_review → pipeline-bus signal emitter (#3147, epic #3143 P2).\n *\n * Emits `signal.fitness_declined` onto the typed pipeline event bus when the\n * fitness audit score falls below the governance floor. Runs in the\n * `improvement_review` MCP tool (server context), so the live shadow TuneStage\n * consumes it. Lives at the MCP layer to keep `governance/fitness-score`\n * decoupled from the pipeline bus, preserving the `A = observability /\n * B = messaging` boundary adopted for #3289 (scope Option 2).\n *\n * @module mcp/tools/improvement-review-signals\n */\n\nimport { getErrorMessage, getTimeProvider } from '../../core/index.js';\nimport type { ILogger } from '../../core/index.js';\nimport type { FitnessAudit } from '../../governance/fitness-score.js';\nimport type { IEventBus } from '../../pipeline/event-types.js';\n\n/** The dimension of the finding that deducted the most points, if any. */\nfunction worstDimension(audit: FitnessAudit): string | undefined {\n let worst: { dimension: string; pointsDeducted: number } | undefined;\n for (const finding of audit.findings) {\n if (worst === undefined || finding.pointsDeducted > worst.pointsDeducted) {\n worst = { dimension: finding.dimension, pointsDeducted: finding.pointsDeducted };\n }\n }\n return worst?.dimension;\n}\n\n/**\n * Emit `signal.fitness_declined` onto `bus` when `audit.score < fitnessFloor`.\n * No-op at or above floor. Emission errors are swallowed and logged — signalling\n * must never break the improvement-review path.\n */\nexport function emitFitnessDeclinedSignal(\n audit: FitnessAudit,\n fitnessFloor: number,\n bus: IEventBus,\n logger: ILogger\n): void {\n if (audit.score >= fitnessFloor) return;\n try {\n const dimension = worstDimension(audit);\n bus.emit({\n type: 'signal.fitness_declined',\n timestamp: getTimeProvider().now(),\n score: audit.score,\n floor: fitnessFloor,\n ...(dimension !== undefined ? { dimension } : {}),\n });\n } catch (error) {\n logger.warn('Failed to emit signal.fitness_declined', { error: getErrorMessage(error) });\n }\n}\n","/**\n * Refined heuristics for the tool-fitness consumer (#3902, refining #3852).\n *\n * Sibling helper module extracted to keep the consumer under the 400-line cap.\n * Owns three signal-quality refinements raised in the #3900 ratification\n * (Contrarian's signal-quality concerns):\n *\n * 1. **Consolidation overlap, not bare prefix** — a shared name-prefix is NOT\n * proof of substitutability (`git_commit` vs `git_init`, `db_read` vs\n * `db_drop_table` share a prefix but are orthogonal). {@link consolidationConfidence}\n * downgrades prefix-only matches to a WEAK/low-confidence hint and withholds\n * the candidate entirely when the tools are orthogonal. As of #3930, a tool's\n * DECLARED {@link ToolManifestEntry.orthogonalityGroup} is authoritative (two\n * different declared groups → orthogonal); the action-verb suffix proxy is the\n * fallback for tools that have not declared a group.\n * 2. **Break-glass exemption** — {@link isNeverDeprecate} exempts low-usage-BY-DESIGN\n * tools (break-glass / safety / integrity) from the `<= 2 invocations`\n * deprecation flag so a rare-but-critical tool isn't surfaced as dead weight.\n * As of #3930, a tool's DECLARED {@link ToolManifestEntry.neverDeprecate} flag\n * is authoritative; the name-substring patterns are the fallback for undeclared\n * tools.\n * 3. **Workspace-scoped localized signal** — instead of FULLY suppressing a\n * cross-workspace-healthy tool's failure, {@link buildLocalizedSignals} emits a\n * workspace-scoped \"failing here\" signal (global deprecation suppressed; the\n * genuine localized misconfig warning still surfaces).\n *\n * EPIC F INVARIANT preserved: every builder here returns a suggest-tier signal\n * (severity `info`/`warning`, never `critical`) routed through the consumer's\n * `assertNeverAutonomousRemoval` guard. Nothing here removes anything.\n *\n * @module mcp/tools/improvement-review-tool-fitness-heuristics\n * (Source: Issue #3902)\n */\n\nimport type { ImprovementSignal } from './improvement-review.js';\nimport type { ToolFitnessStat } from '../../governance/tool-fitness-ledger.js';\nimport {\n declaredOrthogonalityGroup,\n isDeclaredNeverDeprecate,\n} from './tool-manifest.js';\n\n// ============================================================================\n// Honest thresholds (documented per acceptance criteria)\n// ============================================================================\n\n/**\n * Minimum invocations before the success-rate dimension is trustworthy. Below\n * this, a tool is judged on USAGE only (a 1/2-failure tool is noise, not a\n * fitness signal). Mirrors the improvement_review `minSampleSize` philosophy.\n */\nexport const FITNESS_MIN_SAMPLE = 10;\n\n/**\n * At/under this invocation count a tool is a LOW-USAGE deprecation candidate —\n * it is barely being selected, so it may be dead weight against the ~47-tool\n * selection ceiling (epic #3850 narrative). Usage is global by nature, so this\n * is NOT workspace-scoped.\n */\nexport const LOW_USAGE_MAX_INVOCATIONS = 2;\n\n/**\n * Success rate at/under this (with >= {@link FITNESS_MIN_SAMPLE} samples) makes a\n * tool a POOR-RELIABILITY deprecation candidate — it is selected but frequently\n * fails. Workspace-scoped.\n */\nexport const POOR_SUCCESS_RATE_MAX = 0.5;\n\n/**\n * A tool counts as \"healthy in another workspace\" when, scoped to that\n * workspace, its success rate clears this floor over a meaningful sample. Used\n * to suppress a global poor-reliability flag that is really workspace-local.\n */\nexport const HEALTHY_WORKSPACE_SUCCESS_FLOOR = 0.8;\n\n/**\n * Consolidation: within a shared tool-name prefix family (e.g. `research_*`), a\n * member used at/under this FRACTION of the busiest sibling's invocations is a\n * consolidation candidate (could fold into a sibling). Family must have >= 2\n * members and the busiest sibling must clear {@link FITNESS_MIN_SAMPLE} so the\n * comparison isn't noise.\n */\nexport const CONSOLIDATION_USAGE_FRACTION = 0.1;\n\n// ============================================================================\n// SUGGEST-TIER invariant guard (Epic F)\n// ============================================================================\n\n/**\n * Runtime assertion of the Epic-F invariant: a tool-fitness signal is ALWAYS a\n * suggest-tier candidate, never an autonomous removal. Caps severity at\n * `warning` (never `critical`) so the priority classifier can't escalate a\n * fitness signal toward an auto-remediation tier, and pins the category. Throws\n * (loudly, in tests + dev) if a future edit tries to emit a removal-grade\n * signal. Returns the signal unchanged on success for fluent use.\n */\nexport function assertNeverAutonomousRemoval(signal: ImprovementSignal): ImprovementSignal {\n if (signal.category !== 'tool-fitness') {\n throw new Error(\n `tool-fitness invariant: expected category 'tool-fitness', got '${signal.category}'`\n );\n }\n if (signal.severity === 'critical') {\n throw new Error(\n `tool-fitness invariant (Epic F): a tool-fitness signal must be suggest-tier ` +\n `(severity 'info'|'warning'), never 'critical' — removal is NEVER autonomous`\n );\n }\n return signal;\n}\n\n// ============================================================================\n// Item 2 — break-glass / never-deprecate exemption\n// ============================================================================\n\n/**\n * FALLBACK action-verb fragments for tools that have NOT declared\n * `neverDeprecate` in the manifest (#3930). The authoritative signal is the\n * declarative {@link ToolManifestEntry.neverDeprecate} flag, consulted first by\n * {@link isNeverDeprecate}; these substrings remain ONLY as a conservative\n * fail-safe so an UNDECLARED tool whose name screams break-glass\n * (rollback / recovery / emergency admin) is still protected from a\n * `<= 2 invocations` false positive. Matched case-insensitively as a substring\n * of the tool name. Override via {@link NeverDeprecateConfig.extraPatterns} /\n * {@link NeverDeprecateConfig.exemptTools} for repo-specific break-glass tools.\n *\n * Precedence (#3930): declared manifest flag > injected config > these name\n * patterns. Prefer DECLARING `neverDeprecate: true` on the manifest entry over\n * relying on a name match.\n */\nexport const DEFAULT_NEVER_DEPRECATE_PATTERNS: readonly string[] = [\n 'rollback',\n 'recover',\n 'restore',\n 'emergency',\n 'break_glass',\n 'breakglass',\n 'panic',\n 'failover',\n 'disaster',\n 'evacuate',\n 'quarantine',\n];\n\n/** Injectable break-glass exemption config (defaults preserve current behavior + the safe-list). */\nexport interface NeverDeprecateConfig {\n /** Exact tool names that are never deprecation candidates regardless of usage. */\n readonly exemptTools?: readonly string[];\n /** Extra substring patterns appended to {@link DEFAULT_NEVER_DEPRECATE_PATTERNS}. */\n readonly extraPatterns?: readonly string[];\n}\n\n/**\n * True when `tool` is tagged never-deprecate / break-glass and must therefore be\n * EXEMPT from the low-usage deprecation flag (item 2). Pure.\n *\n * Precedence (#3930, declarative-first):\n * 1. **Declared manifest flag** — a tool that DECLARES `neverDeprecate: true`\n * in `TOOL_MANIFEST` is authoritatively protected, regardless of its name.\n * 2. **Injected config** — an explicit `exemptTools` entry protects the tool.\n * 3. **Name-substring fallback** — for UNDECLARED tools only, the documented\n * {@link DEFAULT_NEVER_DEPRECATE_PATTERNS} (+ any `extraPatterns`) still\n * guard a name that screams break-glass. This is the conservative fail-safe:\n * when uncertain, protect (never auto-deprecate).\n */\nexport function isNeverDeprecate(tool: string, config?: NeverDeprecateConfig): boolean {\n // 1. Declarative metadata is authoritative (#3930).\n if (isDeclaredNeverDeprecate(tool)) return true;\n // 2. Caller-injected exemptions.\n if (config?.exemptTools?.includes(tool) === true) return true;\n // 3. Name-substring fallback for tools that have NOT declared.\n const lower = tool.toLowerCase();\n const patterns = [...DEFAULT_NEVER_DEPRECATE_PATTERNS, ...(config?.extraPatterns ?? [])];\n return patterns.some((p) => lower.includes(p));\n}\n\n// ============================================================================\n// Item 1 — consolidation overlap confidence (prefix is only a WEAK hint)\n// ============================================================================\n\n/**\n * Action verbs that mutate/destroy vs. read/create — when two prefix-siblings\n * carry verbs from clearly opposed groups they are ORTHOGONAL (not\n * substitutable), so the prefix match is suppressed entirely.\n *\n * FALLBACK ONLY (#3930): this name-suffix proxy now applies only when at least\n * one of the two tools has NOT declared an\n * {@link ToolManifestEntry.orthogonalityGroup}. A tool's declared group is the\n * authoritative orthogonality signal (consulted first by\n * {@link consolidationConfidence}); this verb-group table is the documented\n * fallback for undeclared tools. Supersedes the former `TODO(#3902)` (declarative\n * capability tags now stand in for the \"true capability-overlap\" seam, while\n * staying conservative — undeclared still surfaces-as-LOW, never high).\n */\nconst ORTHOGONAL_VERB_GROUPS: readonly (readonly string[])[] = [\n ['init', 'create', 'add', 'new', 'open', 'start', 'enable', 'register'],\n ['drop', 'delete', 'remove', 'destroy', 'close', 'stop', 'disable', 'purge'],\n ['read', 'get', 'list', 'query', 'show', 'status', 'inspect'],\n ['commit', 'write', 'update', 'set', 'put', 'apply'],\n];\n\n/** Confidence of a prefix-only consolidation hint. */\nexport type ConsolidationConfidence = 'low' | 'none';\n\n/** The action-verb suffix of a tool name (segment after the family prefix). */\nfunction actionVerb(tool: string): string | undefined {\n const sep = /[_-]/;\n const parts = tool.toLowerCase().split(sep).filter(Boolean);\n return parts.length >= 2 ? parts[1] : undefined;\n}\n\n/** Index of the orthogonal-verb group a verb belongs to, or -1. */\nfunction verbGroup(verb: string | undefined): number {\n if (verb === undefined) return -1;\n return ORTHOGONAL_VERB_GROUPS.findIndex((g) => g.includes(verb));\n}\n\n/**\n * Confidence that a prefix-sharing pair (`candidate`, `busiest`) is genuinely a\n * consolidation candidate.\n *\n * Precedence (#3930, declarative-first):\n * 1. **Declared orthogonality groups** — when BOTH tools declare an\n * {@link ToolManifestEntry.orthogonalityGroup} and the groups DIFFER, they\n * are authoritatively orthogonal (distinct capability domains, e.g. memory\n * read vs write) → `'none'`, do NOT surface. Same declared group → they are\n * genuinely in the same domain, so fall through to the usage-ratio caller as\n * a `'low'` hint.\n * 2. **Action-verb fallback** — when at least one tool has NOT declared a group,\n * use the {@link ORTHOGONAL_VERB_GROUPS} name-suffix proxy: clearly OPPOSED\n * verbs (e.g. `init` vs `drop`) → `'none'`; otherwise `'low'`.\n *\n * Conservative by construction: there is NO `'high'` tier from this signal — an\n * undeclared / unproven pair surfaces as a LOW-CONFIDENCE hint, never hidden via\n * a false-high. Pure.\n */\nexport function consolidationConfidence(\n candidate: ToolFitnessStat,\n busiest: ToolFitnessStat\n): ConsolidationConfidence {\n // 1. Declarative metadata is authoritative (#3930): two DIFFERENT declared\n // groups → orthogonal. (Same group → not orthogonal; fall through to 'low'.)\n const declaredA = declaredOrthogonalityGroup(candidate.tool);\n const declaredB = declaredOrthogonalityGroup(busiest.tool);\n if (declaredA !== undefined && declaredB !== undefined) {\n return declaredA !== declaredB ? 'none' : 'low';\n }\n // 2. Fallback for UNDECLARED tools: action-verb proxy.\n const a = verbGroup(actionVerb(candidate.tool));\n const b = verbGroup(actionVerb(busiest.tool));\n // Both verbs classified and in different opposed groups → orthogonal siblings.\n if (a !== -1 && b !== -1 && a !== b) return 'none';\n return 'low';\n}\n\n// ============================================================================\n// Suggest-tier signal builders (all routed through the Epic-F guard)\n// ============================================================================\n\n/** Build a low-usage deprecation candidate signal (suggest-tier). */\nexport function lowUsageSignal(stat: ToolFitnessStat, windowLabel: string): ImprovementSignal {\n return assertNeverAutonomousRemoval({\n category: 'tool-fitness',\n signalKey: `tool-fitness:deprecation-candidate:low-usage:${stat.tool}`,\n severity: 'info',\n title: `tool-fitness: \\`${stat.tool}\\` is a low-usage deprecation CANDIDATE (${String(stat.invocationCount)} invocations)`,\n body: [\n `\\`${stat.tool}\\` is barely selected and is a CANDIDATE for human review — NOT an automatic removal.`,\n '',\n `- Invocations: ${String(stat.invocationCount)} (threshold: ≤ ${String(LOW_USAGE_MAX_INVOCATIONS)})`,\n `- Last used: ${stat.lastUsedAt}`,\n `- Success rate: ${String(Math.round(stat.successRate * 100))}%`,\n `- Window: ${windowLabel}`,\n '',\n 'SUGGEST-TIER ONLY (Epic F): low usage against the ~47-tool selection ceiling ' +\n 'may mean dead weight. Removal is NEVER autonomous — it requires the Epic D ' +\n 'human-ratification path (see the #3853 removal/consolidation runbook). ' +\n 'Mind the LinUCB exploration floor: a low-usage tool must not death-spiral.',\n ].join('\\n'),\n evidence: {\n samples: stat.invocationCount,\n window: windowLabel,\n observedValue: stat.invocationCount,\n threshold: LOW_USAGE_MAX_INVOCATIONS,\n },\n });\n}\n\n/** Build a poor-reliability deprecation candidate signal (suggest-tier). */\nexport function poorReliabilitySignal(\n stat: ToolFitnessStat,\n windowLabel: string\n): ImprovementSignal {\n return assertNeverAutonomousRemoval({\n category: 'tool-fitness',\n signalKey: `tool-fitness:deprecation-candidate:poor-success:${stat.tool}`,\n severity: 'warning',\n title: `tool-fitness: \\`${stat.tool}\\` has a low success rate ${String(Math.round(stat.successRate * 100))}% — deprecation CANDIDATE`,\n body: [\n `\\`${stat.tool}\\` fails often across its uses and is a CANDIDATE for human review — NOT an automatic removal.`,\n '',\n `- Success rate: ${String(Math.round(stat.successRate * 100))}% (${String(stat.successCount)}/${String(stat.invocationCount)}, threshold ≤ ${String(Math.round(POOR_SUCCESS_RATE_MAX * 100))}%)`,\n `- Samples: ${String(stat.invocationCount)} (≥ ${String(FITNESS_MIN_SAMPLE)} required)`,\n `- Workspaces observed: ${stat.workspaces.join(', ')}`,\n `- Window: ${windowLabel}`,\n '',\n 'Workspace-scoped (#3852): this fires only because the tool is unhealthy across ' +\n 'workspaces, not just one — a single-workspace failure (local perms / missing ' +\n 'deps) is suppressed so it cannot globally mis-flag a healthy tool.',\n '',\n 'SUGGEST-TIER ONLY (Epic F): consider consolidating or deprecating after human ' +\n 'review. Removal is NEVER autonomous — Epic D ratification (#3853 runbook).',\n ].join('\\n'),\n evidence: {\n samples: stat.invocationCount,\n window: windowLabel,\n observedValue: stat.successRate,\n threshold: POOR_SUCCESS_RATE_MAX,\n },\n });\n}\n\n/**\n * Build a WORKSPACE-SCOPED localized reliability signal (#3902 item 3). Emitted\n * when a tool's poor GLOBAL rate was suppressed as context-poisoning (healthy\n * elsewhere) BUT it is genuinely failing in `workspace` — the global deprecation\n * stays suppressed, yet the localized \"failing here\" misconfig warning still\n * surfaces instead of being fully silenced. Suggest-tier; explicitly NOT a\n * deprecation candidate.\n */\nexport function localizedReliabilitySignal(\n scoped: ToolFitnessStat,\n workspace: string,\n windowLabel: string\n): ImprovementSignal {\n return assertNeverAutonomousRemoval({\n category: 'tool-fitness',\n signalKey: `tool-fitness:localized-failure:${scoped.tool}:${workspace}`,\n severity: 'warning',\n title: `tool-fitness: \\`${scoped.tool}\\` is failing in workspace \\`${workspace}\\` (healthy elsewhere)`,\n body: [\n `\\`${scoped.tool}\\` is healthy in other workspaces, so this is NOT a global deprecation ` +\n `candidate. But it fails locally in \\`${workspace}\\` — a likely LOCALIZED misconfig ` +\n `(local perms / missing deps / repo-specific config) worth investigating HERE.`,\n '',\n `- Workspace: ${workspace}`,\n `- Local success rate: ${String(Math.round(scoped.successRate * 100))}% (${String(scoped.successCount)}/${String(scoped.invocationCount)}, threshold ≤ ${String(Math.round(POOR_SUCCESS_RATE_MAX * 100))}%)`,\n `- Local samples: ${String(scoped.invocationCount)} (≥ ${String(FITNESS_MIN_SAMPLE)} required)`,\n `- Window: ${windowLabel}`,\n '',\n 'WORKSPACE-SCOPED (#3902): cross-workspace suppression fixes context-poisoning but ' +\n 'should not discard a genuine localized warning. This surfaces the local failure ' +\n 'WITHOUT globally mis-flagging a tool that is healthy elsewhere.',\n '',\n 'SUGGEST-TIER ONLY (Epic F): a localized diagnostic for human review — never an ' +\n 'autonomous removal. Removal is Epic D ratification (#3853 runbook).',\n ].join('\\n'),\n evidence: {\n samples: scoped.invocationCount,\n window: windowLabel,\n observedValue: scoped.successRate,\n threshold: POOR_SUCCESS_RATE_MAX,\n },\n });\n}\n\n/** Build a consolidation candidate signal (suggest-tier, LOW-CONFIDENCE per #3902). */\nexport function consolidationSignal(\n stat: ToolFitnessStat,\n family: string,\n busiestTool: string,\n busiestCount: number,\n windowLabel: string\n): ImprovementSignal {\n return assertNeverAutonomousRemoval({\n category: 'tool-fitness',\n signalKey: `tool-fitness:consolidation-candidate:${stat.tool}`,\n severity: 'info',\n title: `tool-fitness: \\`${stat.tool}\\` is a LOW-CONFIDENCE consolidation CANDIDATE within the \\`${family}_*\\` family`,\n body: [\n `\\`${stat.tool}\\` is far less used than its \\`${family}_*\\` siblings and is a CANDIDATE ` +\n `for folding into a sibling — for human review, NOT an automatic removal.`,\n '',\n `- This tool: ${String(stat.invocationCount)} invocations`,\n `- Busiest sibling \\`${busiestTool}\\`: ${String(busiestCount)} invocations`,\n `- Ratio: ${String(Math.round((stat.invocationCount / busiestCount) * 100))}% (threshold ≤ ${String(Math.round(CONSOLIDATION_USAGE_FRACTION * 100))}%)`,\n `- Window: ${windowLabel}`,\n `- Confidence: LOW (#3902) — a shared name-prefix is a WEAK hint, NOT proof of`,\n ' substitutability. The orthogonal-action-verb check passed (siblings are not',\n ' obviously opposed like `init` vs `drop`), but no capability/schema-overlap',\n ' signal exists yet to confirm these tools are actually interchangeable.',\n '',\n 'SUGGEST-TIER ONLY (Epic F): overlapping tools inflate the selection surface. ' +\n 'Consolidation is a human decision via the Epic D path (#3853 runbook); nothing ' +\n 'here removes or merges anything automatically.',\n ].join('\\n'),\n evidence: {\n samples: stat.invocationCount,\n window: windowLabel,\n observedValue: stat.invocationCount / busiestCount,\n threshold: CONSOLIDATION_USAGE_FRACTION,\n },\n });\n}\n","/**\n * Tool-fitness ledger — data layer (#3851, child of epic #3850).\n *\n * Records per-tool fitness signals so a later consumer can reason about which\n * of the ~47 MCP tools are pulling their weight. Each MCP invocation (seen by\n * the tool-wrapper / secure-handler middleware) can be appended as one fitness\n * event; the ledger aggregates events into a per-tool stat — invocation count,\n * last-used timestamp, success/failure correlation, and a cost placeholder\n * (full cost lands with Epic G).\n *\n * ## Persistence idiom\n *\n * This MIRRORS the established durable-telemetry idiom rather than inventing a\n * parallel one:\n *\n * - Storage is the shared {@link JsonlStore} primitive (`config/jsonl-store`,\n * #3762) — the same hydrate-on-construct / append-on-write / Zod-validate-\n * each-line mechanism that backs {@link PersistentOutcomeStore} and the\n * `ci-health` event log. Bounded by oldest-eviction rotation so the file can\n * never grow without limit (the #3089 size-cap concern).\n * - The path resolves via {@link nexusDataPath} at `tool-fitness/ledger.jsonl`.\n * `tool-fitness` is NOT in `PER_REPO_SUBDIRS`, so it routes cross-repo\n * (homedir-scoped) — tool fitness accumulates across the operator's whole\n * workflow, like the learning/usage state, not per-codebase like `runs`.\n * - Append is best-effort: a telemetry sink must never throw into the operation\n * it observes (inherited from the JsonlStore contract).\n *\n * ## Concurrency (#3852 concern 2)\n *\n * {@link JsonlStore} (the shared #3762 primitive behind PersistentOutcomeStore)\n * uses Node's synchronous `appendFileSync` for the fast path. On Linux a single\n * `write(2)` of a sub-`PIPE_BUF` line to a file opened `O_APPEND` is atomic, so\n * two processes appending to the homedir-shared ledger interleave at line\n * granularity rather than corrupting a line — and the hydrate path already skips\n * any partially-written/corrupt line (graceful degradation). The RESIDUAL is the\n * over-cap **rewrite** path ({@link JsonlStore.rewriteFile}): a full-file\n * `writeFileSync` is NOT coordinated across processes, so two concurrent\n * rewrites can race and one can lose the other's just-appended lines. This is a\n * PRE-EXISTING property of the shared primitive (inherited from #3762, same as\n * PersistentOutcomeStore), not introduced here. It is acceptable for THIS\n * consumer because the surfaced signal is suggest-tier only (a lossy line here\n * or there cannot cause an autonomous action) and the loss is bounded to events\n * near the rotation boundary. See the concurrency test in the test file.\n *\n * ## Scope\n *\n * DATA LAYER (+ consumed by #3852). This module owns the tool-fitness schema and\n * aggregation. The `tool-fitness` SignalCategory consumer now lives in\n * `improvement_review` (#3852) — so this producer HAS a real in-src consumer and\n * no longer carries the `@export-no-consumer-yet` marker. It still does NOT\n * implement any pruning/removal pipeline — that is later in epic #3850 and is\n * NEVER autonomous (human ratification via the Epic D path).\n *\n * @module governance/tool-fitness-ledger\n */\n\nimport { z } from 'zod';\n\nimport { JsonlStore } from '../config/jsonl-store.js';\nimport { nexusDataPath } from '../config/nexus-data-dir.js';\n\n// ============================================================================\n// Schemas\n// ============================================================================\n\n/**\n * One recorded fitness event for a single tool invocation. Versioned (`v`) for\n * forward-compatible on-disk evolution, matching the `ci-health` event idiom.\n */\nexport const ToolFitnessEventSchema = z.object({\n /** Schema version. Forward-compat for on-disk evolution. */\n v: z.literal(1),\n /** ISO-8601 timestamp of the invocation. */\n ts: z.iso.datetime(),\n /** Tool identifier (e.g. the MCP tool name). */\n tool: z.string().min(1).max(100),\n /** Whether the invocation succeeded. Drives the success/failure correlation. */\n success: z.boolean(),\n /**\n * Cost of the invocation in arbitrary units (e.g. tokens), when the calling\n * surface exposes it. Placeholder until full cost accounting lands with\n * Epic G — absent (not zero) when unknown so aggregates don't conflate\n * \"free\" with \"unmeasured\".\n */\n cost: z.number().nonnegative().optional(),\n /**\n * OPTIONAL workspace/repo dimension (#3852 concern 1 — context-poisoning).\n * The ledger is homedir-global, so a tool that fails only in ONE workspace\n * (local perms, missing deps, repo-specific config) would otherwise aggregate\n * into a single global fitness number and could wrongly flag a tool that is\n * healthy everywhere else. Recording the originating workspace lets the\n * consumer scope/weight fitness so a one-workspace failure doesn't get\n * globally penalized. BACKWARD-COMPATIBLE: optional, absent on legacy events\n * (treated as the unattributed/global bucket by the consumer).\n */\n workspace: z.string().min(1).max(256).optional(),\n});\nexport type ToolFitnessEvent = z.infer<typeof ToolFitnessEventSchema>;\n\n/** Aggregated fitness stats for a single tool. */\nexport interface ToolFitnessStat {\n /** Tool identifier. */\n readonly tool: string;\n /** Total recorded invocations. */\n readonly invocationCount: number;\n /** Count where `success === true`. */\n readonly successCount: number;\n /** Count where `success === false`. */\n readonly failureCount: number;\n /**\n * `successCount / invocationCount`. `0` when `invocationCount === 0`\n * (which cannot occur for a returned stat, but keeps the type total).\n */\n readonly successRate: number;\n /** ISO-8601 timestamp of the most recent invocation. */\n readonly lastUsedAt: string;\n /**\n * Sum of `cost` across events that carried one. `undefined` when NO event\n * for this tool reported a cost — distinguishes \"unmeasured\" from \"zero\".\n */\n readonly totalCost: number | undefined;\n /**\n * Distinct workspaces that recorded an event for this tool (#3852 concern 1).\n * Sorted, deduped. Events with no `workspace` contribute the sentinel\n * {@link UNATTRIBUTED_WORKSPACE}. The consumer uses this to scope fitness:\n * a tool failing in ONE workspace but healthy in others is NOT a global\n * deprecation candidate.\n */\n readonly workspaces: readonly string[];\n}\n\n/** Sentinel bucket for events that carried no `workspace` (legacy/global). */\nexport const UNATTRIBUTED_WORKSPACE = '(unattributed)';\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\n/**\n * Default retained-event cap. Bounds disk + hydrate cost of an unbounded\n * append loop (the #3089 concern). Tunable per-instance via\n * {@link ToolFitnessLedgerConfig.maxEvents} for tests.\n */\nconst DEFAULT_MAX_EVENTS = 50_000;\n\n/** Subdir + file name under the nexus data dir (cross-repo / homedir-scoped). */\nconst LEDGER_SUBDIR = 'tool-fitness';\nconst LEDGER_FILE = 'ledger.jsonl';\n\nexport interface ToolFitnessLedgerConfig {\n /**\n * Absolute path to the JSONL file. Defaults to\n * `<nexusDataDir>/tool-fitness/ledger.jsonl`. Pass an explicit path in tests\n * to isolate from the real data dir.\n */\n readonly filePath?: string;\n /** Max retained events before oldest-eviction. Defaults to {@link DEFAULT_MAX_EVENTS}. */\n readonly maxEvents?: number;\n}\n\n// ============================================================================\n// Ledger\n// ============================================================================\n\n/**\n * Per-tool fitness ledger. A thin record/aggregate/query API over the shared\n * {@link JsonlStore} primitive — it owns the tool-fitness SCHEMA and the\n * aggregation, and delegates all persistence plumbing to JsonlStore.\n */\nexport class ToolFitnessLedger {\n private readonly store: JsonlStore<ToolFitnessEvent>;\n\n constructor(config?: ToolFitnessLedgerConfig) {\n this.store = new JsonlStore<ToolFitnessEvent>({\n filePath: config?.filePath ?? nexusDataPath(LEDGER_SUBDIR, LEDGER_FILE),\n schema: ToolFitnessEventSchema,\n maxRecords: config?.maxEvents ?? DEFAULT_MAX_EVENTS,\n component: 'ToolFitnessLedger',\n });\n }\n\n /**\n * Record one tool invocation. `v`/`ts` are stamped here so callers pass only\n * the observed signal. Best-effort durability (inherited from JsonlStore):\n * never throws into the observed operation.\n */\n record(event: {\n tool: string;\n success: boolean;\n cost?: number;\n /**\n * Originating workspace/repo (#3852 concern 1). Optional + backward-compat:\n * absent events fall into the {@link UNATTRIBUTED_WORKSPACE} bucket.\n */\n workspace?: string;\n /** Override the timestamp (defaults to now). Mainly for tests/backfill. */\n ts?: string;\n }): void {\n const record: ToolFitnessEvent = {\n v: 1,\n ts: event.ts ?? new Date().toISOString(),\n tool: event.tool,\n success: event.success,\n ...(event.cost !== undefined ? { cost: event.cost } : {}),\n ...(event.workspace !== undefined ? { workspace: event.workspace } : {}),\n };\n this.store.append(record);\n }\n\n /** Total retained events across all tools. */\n size(): number {\n return this.store.count();\n }\n\n /**\n * Aggregate stats for a single tool, or `undefined` when the tool has no\n * recorded events (unknown tool / empty ledger). Pure over the current\n * event set — no I/O.\n */\n statFor(tool: string): ToolFitnessStat | undefined {\n const events = this.store.all().filter((e) => e.tool === tool);\n if (events.length === 0) return undefined;\n return aggregate(tool, events);\n }\n\n /**\n * Aggregate stats for a single tool RESTRICTED to one workspace (#3852\n * concern 1 — context-poisoning). Pass {@link UNATTRIBUTED_WORKSPACE} to\n * select the legacy/global bucket of events that carried no `workspace`.\n * Returns `undefined` when the tool has no events in that workspace.\n *\n * This is the primitive that lets the consumer answer \"is this tool low-fitness\n * EVERYWHERE, or only in one repo?\" so a single-workspace failure can't\n * globally mis-flag a healthy tool.\n */\n statForInWorkspace(tool: string, workspace: string): ToolFitnessStat | undefined {\n const events = this.store\n .all()\n .filter((e) => e.tool === tool && (e.workspace ?? UNATTRIBUTED_WORKSPACE) === workspace);\n if (events.length === 0) return undefined;\n return aggregate(tool, events);\n }\n\n /**\n * Aggregate stats for every tool with at least one event, sorted by\n * descending invocation count (most-used first) then tool name for a stable\n * order. Returns `[]` for an empty ledger.\n */\n report(): readonly ToolFitnessStat[] {\n const byTool = new Map<string, ToolFitnessEvent[]>();\n for (const event of this.store.all()) {\n const bucket = byTool.get(event.tool);\n if (bucket === undefined) byTool.set(event.tool, [event]);\n else bucket.push(event);\n }\n const stats: ToolFitnessStat[] = [];\n for (const [tool, events] of byTool) {\n stats.push(aggregate(tool, events));\n }\n stats.sort((a, b) => b.invocationCount - a.invocationCount || a.tool.localeCompare(b.tool));\n return stats;\n }\n}\n\n// ============================================================================\n// Pure aggregation\n// ============================================================================\n\n/**\n * Fold a non-empty event list for one tool into a {@link ToolFitnessStat}.\n * Pure (fixture-testable): same input always yields the same output.\n */\nfunction aggregate(tool: string, events: readonly ToolFitnessEvent[]): ToolFitnessStat {\n let successCount = 0;\n let lastUsedAt = '';\n let totalCost: number | undefined;\n const workspaces = new Set<string>();\n for (const event of events) {\n if (event.success) successCount++;\n if (lastUsedAt === '' || Date.parse(event.ts) >= Date.parse(lastUsedAt)) lastUsedAt = event.ts;\n if (event.cost !== undefined) totalCost = (totalCost ?? 0) + event.cost;\n workspaces.add(event.workspace ?? UNATTRIBUTED_WORKSPACE);\n }\n const invocationCount = events.length;\n return {\n tool,\n invocationCount,\n successCount,\n failureCount: invocationCount - successCount,\n successRate: successCount / invocationCount,\n lastUsedAt,\n totalCost,\n workspaces: [...workspaces].sort((a, b) => a.localeCompare(b)),\n };\n}\n\n// ============================================================================\n// Singleton\n// ============================================================================\n\nlet singleton: ToolFitnessLedger | undefined;\n\n/**\n * Process-wide ledger backed by the default on-disk path. Lazily constructed\n * so tests that never touch it don't create a data dir. Tests that DO exercise\n * persistence should construct their own {@link ToolFitnessLedger} with an\n * explicit `filePath` to stay isolated.\n */\nexport function getToolFitnessLedger(): ToolFitnessLedger {\n singleton ??= new ToolFitnessLedger();\n return singleton;\n}\n\n/** Test helper — drops the process singleton so the next get reconstructs it. */\nexport function _resetToolFitnessLedgerForTests(): void {\n singleton = undefined;\n}\n","/**\n * Tool-fitness SignalCategory consumer for `improvement_review` (#3852, child of\n * epic #3850). This is the NAMED consumer of the #3851 tool-fitness ledger.\n *\n * Reads the per-tool fitness ledger ({@link ToolFitnessLedger.report}) and\n * surfaces two kinds of suggest-tier candidate:\n *\n * - **Deprecation candidates** — a tool with very low recent invocations AND/OR\n * a poor success rate over a meaningful sample. \"Pulling its weight\" is judged\n * by usage + reliability, never intuition.\n * - **Consolidation candidates** — tools whose names indicate an overlapping\n * surface (a shared prefix family, e.g. `research_*`) where one member is far\n * less used than its siblings, hinting it could fold into a sibling. (Richer\n * tool-distinctness similarity data is a later seam; this is the honest,\n * ledger-only heuristic for the first consumer.)\n *\n * ## EPIC F INVARIANT — NEVER autonomous removal\n *\n * Output is **SUGGEST-TIER ONLY**. Every signal this module produces is a\n * *candidate for human review*, NOT an instruction to prune. The strings are\n * deliberately worded as candidates, severity caps at `warning` (never\n * `critical`, which would escalate priority toward auto-remediation), and the\n * shared `improvement_review` contract keeps `fileIssues=false` by default with\n * a rate cap. Removal requires the Epic D human-ratification path (#3853\n * runbook). {@link assertNeverAutonomousRemoval} encodes this as a runtime\n * guard the tests assert against.\n *\n * ## Context-poisoning defense (#3852 concern 1)\n *\n * The ledger is homedir-global, so a tool that fails in ONE workspace would\n * otherwise aggregate into a single global number and mis-flag a tool that is\n * healthy everywhere else. Before flagging a low-success tool, this consumer\n * checks the per-workspace breakdown: if the tool is healthy in any OTHER\n * workspace, the failure is workspace-local and does NOT produce a global\n * deprecation signal (it is reported as workspace-scoped context instead). A\n * low-USAGE candidate is workspace-agnostic (usage is genuinely global), so\n * scoping applies to the success-rate dimension where poisoning actually bites.\n *\n * @module mcp/tools/improvement-review-tool-fitness\n * (Source: Issue #3852)\n */\n\nimport type { ImprovementSignal } from './improvement-review.js';\nimport {\n assertNeverAutonomousRemoval,\n consolidationConfidence,\n consolidationSignal,\n CONSOLIDATION_USAGE_FRACTION,\n FITNESS_MIN_SAMPLE,\n HEALTHY_WORKSPACE_SUCCESS_FLOOR,\n isNeverDeprecate,\n localizedReliabilitySignal,\n lowUsageSignal,\n LOW_USAGE_MAX_INVOCATIONS,\n poorReliabilitySignal,\n POOR_SUCCESS_RATE_MAX,\n type NeverDeprecateConfig,\n} from './improvement-review-tool-fitness-heuristics.js';\nimport {\n getToolFitnessLedger,\n ToolFitnessLedger,\n UNATTRIBUTED_WORKSPACE,\n type ToolFitnessStat,\n} from '../../governance/tool-fitness-ledger.js';\n\n// Re-export the thresholds + Epic-F guard so existing consumers/tests keep their\n// import surface (the constants & guard now live in the heuristics sibling so\n// this consumer stays under the 400-line cap, #3902).\nexport {\n assertNeverAutonomousRemoval,\n CONSOLIDATION_USAGE_FRACTION,\n FITNESS_MIN_SAMPLE,\n HEALTHY_WORKSPACE_SUCCESS_FLOOR,\n LOW_USAGE_MAX_INVOCATIONS,\n POOR_SUCCESS_RATE_MAX,\n};\nexport type { NeverDeprecateConfig };\n\n// ============================================================================\n// Pure detection logic (fixture-testable — no fs, no ledger I/O)\n// ============================================================================\n\n/**\n * True when `stat` is healthy in at least one workspace OTHER than the one(s)\n * dragging its global rate down — i.e. the poor global rate is workspace-local\n * context-poisoning, so it must NOT produce a global deprecation flag.\n *\n * Pure: takes a `statInWorkspace` resolver so it's testable without a ledger.\n */\nexport function isHealthyInAnyOtherWorkspace(\n stat: ToolFitnessStat,\n statInWorkspace: (tool: string, workspace: string) => ToolFitnessStat | undefined\n): boolean {\n // Single (or zero) workspace → nothing to scope against; not poisoning.\n const realWorkspaces = stat.workspaces.filter((w) => w !== UNATTRIBUTED_WORKSPACE);\n if (realWorkspaces.length < 2) return false;\n return realWorkspaces.some((ws) => {\n const scoped = statInWorkspace(stat.tool, ws);\n return (\n scoped !== undefined &&\n scoped.invocationCount >= FITNESS_MIN_SAMPLE &&\n scoped.successRate >= HEALTHY_WORKSPACE_SUCCESS_FLOOR\n );\n });\n}\n\n/**\n * Workspaces where `stat` is genuinely failing LOCALLY (#3902 item 3): scoped\n * success rate at/under {@link POOR_SUCCESS_RATE_MAX} over a meaningful sample.\n * Used to surface a localized warning when the global flag is suppressed as\n * context-poisoning. Pure (resolver injected). Returns the failing scoped stats.\n */\nexport function locallyFailingWorkspaces(\n stat: ToolFitnessStat,\n statInWorkspace: (tool: string, workspace: string) => ToolFitnessStat | undefined\n): readonly ToolFitnessStat[] {\n const realWorkspaces = stat.workspaces.filter((w) => w !== UNATTRIBUTED_WORKSPACE);\n const failing: ToolFitnessStat[] = [];\n for (const ws of realWorkspaces) {\n const scoped = statInWorkspace(stat.tool, ws);\n if (\n scoped !== undefined &&\n scoped.invocationCount >= FITNESS_MIN_SAMPLE &&\n scoped.successRate <= POOR_SUCCESS_RATE_MAX\n ) {\n failing.push(scoped);\n }\n }\n return failing;\n}\n\n/** Tool-name family = prefix before the first underscore (e.g. `research`). */\nfunction toolFamily(tool: string): string | undefined {\n const idx = tool.indexOf('_');\n return idx > 0 ? tool.slice(0, idx) : undefined;\n}\n\n/** Group report stats by shared-prefix family (tools with no prefix dropped). */\nfunction groupByFamily(report: readonly ToolFitnessStat[]): Map<string, ToolFitnessStat[]> {\n const families = new Map<string, ToolFitnessStat[]>();\n for (const stat of report) {\n const fam = toolFamily(stat.tool);\n if (fam === undefined) continue;\n const bucket = families.get(fam);\n if (bucket === undefined) families.set(fam, [stat]);\n else bucket.push(stat);\n }\n return families;\n}\n\n/** The busiest member of a non-empty family by invocation count. */\nfunction busiestMember(members: readonly ToolFitnessStat[]): ToolFitnessStat {\n return members.reduce((best, m) => (m.invocationCount > best.invocationCount ? m : best));\n}\n\n/**\n * Consolidation candidates within ONE family (busiest already cleared the floor).\n * #3902: a shared prefix is only a WEAK hint — a member is dropped when its\n * action verb is clearly ORTHOGONAL to the busiest sibling's (e.g. `git_init`\n * vs `git_commit`, `db_read` vs `db_drop_table`), so a rare sibling is never\n * flagged for folding into a busy one on prefix alone. Survivors are emitted as\n * LOW-CONFIDENCE candidates (see {@link consolidationSignal}).\n */\nfunction familyConsolidationSignals(\n members: readonly ToolFitnessStat[],\n family: string,\n busiest: ToolFitnessStat,\n windowLabel: string\n): readonly ImprovementSignal[] {\n const cutoff = busiest.invocationCount * CONSOLIDATION_USAGE_FRACTION;\n return members\n .filter((m) => m.tool !== busiest.tool && m.invocationCount <= cutoff)\n .filter((m) => consolidationConfidence(m, busiest) !== 'none')\n .map((m) => consolidationSignal(m, family, busiest.tool, busiest.invocationCount, windowLabel));\n}\n\n/**\n * Detect consolidation candidates: within each shared-prefix family with >= 2\n * members where the busiest sibling clears the sample floor, flag members used\n * at/under {@link CONSOLIDATION_USAGE_FRACTION} of the busiest. Pure.\n */\nexport function detectConsolidationCandidates(\n report: readonly ToolFitnessStat[],\n windowLabel: string\n): readonly ImprovementSignal[] {\n const signals: ImprovementSignal[] = [];\n for (const [family, members] of groupByFamily(report)) {\n if (members.length < 2) continue;\n const busiest = busiestMember(members);\n if (busiest.invocationCount < FITNESS_MIN_SAMPLE) continue;\n signals.push(...familyConsolidationSignals(members, family, busiest, windowLabel));\n }\n return signals;\n}\n\n/** Reliability signals for one stat: global poor-reliability OR localized failures. */\nfunction reliabilitySignalsFor(\n stat: ToolFitnessStat,\n statInWorkspace: (tool: string, workspace: string) => ToolFitnessStat | undefined,\n windowLabel: string\n): readonly ImprovementSignal[] {\n if (stat.invocationCount < FITNESS_MIN_SAMPLE || stat.successRate > POOR_SUCCESS_RATE_MAX) {\n return [];\n }\n // #3902 item 3: when healthy elsewhere, the global flag is suppressed BUT the\n // localized \"failing here\" warning still surfaces (don't fully silence it).\n if (isHealthyInAnyOtherWorkspace(stat, statInWorkspace)) {\n return locallyFailingWorkspaces(stat, statInWorkspace).map((scoped) =>\n localizedReliabilitySignal(\n scoped,\n scoped.workspaces[0] ?? UNATTRIBUTED_WORKSPACE,\n windowLabel\n )\n );\n }\n return [poorReliabilitySignal(stat, windowLabel)];\n}\n\n/**\n * Detect deprecation candidates (low usage OR poor reliability) from a fitness\n * report, scoping the reliability dimension by workspace to defeat\n * context-poisoning. #3902: low-usage break-glass tools are EXEMPT (item 2), and\n * a cross-workspace-suppressed failure still emits a workspace-scoped localized\n * signal (item 3). Pure: the `statInWorkspace` resolver is injected.\n */\nexport function detectDeprecationCandidates(\n report: readonly ToolFitnessStat[],\n statInWorkspace: (tool: string, workspace: string) => ToolFitnessStat | undefined,\n windowLabel: string,\n neverDeprecate?: NeverDeprecateConfig\n): readonly ImprovementSignal[] {\n const signals: ImprovementSignal[] = [];\n for (const stat of report) {\n if (stat.invocationCount <= LOW_USAGE_MAX_INVOCATIONS) {\n // #3902 item 2: break-glass / never-deprecate tools are low-usage BY DESIGN.\n if (isNeverDeprecate(stat.tool, neverDeprecate)) continue;\n signals.push(lowUsageSignal(stat, windowLabel));\n continue; // low-usage already covers it; don't double-flag.\n }\n signals.push(...reliabilitySignalsFor(stat, statInWorkspace, windowLabel));\n }\n return signals;\n}\n\n/**\n * Full tool-fitness signal set from a report. Combines deprecation +\n * consolidation candidates. Pure (no ledger I/O) — used directly in fixture\n * tests; {@link loadToolFitnessSignals} wires it to the live ledger.\n */\nexport function detectToolFitnessSignals(\n report: readonly ToolFitnessStat[],\n statInWorkspace: (tool: string, workspace: string) => ToolFitnessStat | undefined,\n windowLabel: string,\n neverDeprecate?: NeverDeprecateConfig\n): readonly ImprovementSignal[] {\n return [\n ...detectDeprecationCandidates(report, statInWorkspace, windowLabel, neverDeprecate),\n ...detectConsolidationCandidates(report, windowLabel),\n ];\n}\n\n/**\n * Read the live tool-fitness ledger and produce suggest-tier signals. Fail-soft:\n * any ledger error yields NO signals (the review must never break on a\n * telemetry read). The ledger is injectable for tests.\n */\nexport function loadToolFitnessSignals(\n windowLabel: string,\n ledger: Pick<ToolFitnessLedger, 'report' | 'statForInWorkspace'> = getToolFitnessLedger()\n): readonly ImprovementSignal[] {\n try {\n const report = ledger.report();\n return detectToolFitnessSignals(\n report,\n (tool, ws) => ledger.statForInWorkspace(tool, ws),\n windowLabel\n );\n } catch {\n return [];\n }\n}\n","/**\n * Deterministic performance-regression detector for `improvement_review`\n * (#3692 + #3246, design-vote Option A).\n *\n * Maps a benchmark measurement against a STATIC, PINNED baseline + a fixed\n * tolerance to an optional `perf-regression` {@link ImprovementSignal}. This is\n * the deterministic core of the observability-feedback cluster: same inputs →\n * same output, NO model judgment.\n *\n * LOAD-BEARING CONSTRAINT (why this is deterministic and NOT #3230 auto-tuning):\n * the baseline is STATIC — supplied by a configured/committed baseline map, never\n * derived from a rolling window over the OutcomeStore or recent runs. A rolling\n * baseline would reintroduce the deferred #3230 adaptive control. If no baseline\n * is configured for a component+operation, this emits NOTHING (conservative — a\n * missing baseline is \"unknown\", never \"regressed\"), so it cannot invent a\n * regression from recent data.\n *\n * SURFACED-NOT-AUTO-ACTED: this module only BUILDS signals. The returned\n * signals are spread into `improvement_review`'s surfaced-signals list exactly\n * like the tech-debt / tool-fitness / below-floor signals. Nothing here mutates a\n * fitness or governance score, applies a penalty, or takes any autonomous action.\n *\n * @module mcp/tools/improvement-review-perf-regression\n * (Source: Issue #3692, #3246)\n */\n\nimport type { ImprovementSignal } from './improvement-review.js';\nimport type { BenchmarkSuiteResult } from '../../benchmarks/benchmark-types.js';\n\n/**\n * A static, pinned baseline for one benchmarked component+operation. These values\n * are CONFIGURED/COMMITTED (e.g. a baseline field in benchmark config or a\n * versioned baseline file) — they are never auto-derived from recent runs.\n */\nexport interface PerfBaseline {\n /**\n * Baseline p95 latency in milliseconds. A measured p95 above\n * `baselineP95Ms * (1 + tolerance)` is a latency regression. Omit to skip the\n * latency check for this operation.\n */\n readonly baselineP95Ms?: number;\n /**\n * Baseline throughput in ops/second. A measured throughput below\n * `baselineThroughput * (1 - tolerance)` is a throughput regression. Omit to\n * skip the throughput check for this operation.\n */\n readonly baselineThroughput?: number;\n}\n\n/**\n * Static baseline map keyed by `\"<component>::<operation>\"`. A component+operation\n * with NO entry here produces no signal (conservative — no false regressions).\n * Construct the key with {@link baselineKey}.\n */\nexport type PerfBaselineMap = ReadonlyMap<string, PerfBaseline>;\n\n/**\n * Documented default regression tolerance: a measurement may be up to 20% worse\n * than baseline before it is flagged. 0.2 = 20% worse than baseline.\n */\nexport const DEFAULT_REGRESSION_TOLERANCE_FRACTION = 0.2;\n\n/** Stable key for the {@link PerfBaselineMap}: `\"<component>::<operation>\"`. */\nexport function baselineKey(component: string, operation: string): string {\n return `${component}::${operation}`;\n}\n\n/** Round to 2 decimals for stable, readable signal payloads. */\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\n/** Percentage delta worse-than-baseline, rounded, for the signal body. */\nfunction pctWorse(measured: number, baseline: number): number {\n if (baseline === 0) return 0;\n return round2((Math.abs(measured - baseline) / baseline) * 100);\n}\n\n/**\n * Build a latency-regression signal. Boundary is EXCLUSIVE: fires only when\n * `measuredP95Ms > baselineP95Ms * (1 + tolerance)` — exactly at the threshold is\n * NOT a regression (conservative).\n */\nfunction latencyRegressionSignal(\n component: string,\n operation: string,\n measuredP95Ms: number,\n baselineP95Ms: number,\n tolerance: number\n): ImprovementSignal | undefined {\n const threshold = baselineP95Ms * (1 + tolerance);\n if (measuredP95Ms <= threshold) return undefined;\n const deltaPct = pctWorse(measuredP95Ms, baselineP95Ms);\n return {\n category: 'perf-regression',\n signalKey: `perf-regression:latency:${component}:${operation}`,\n severity: 'warning',\n title: `perf-regression: ${component}/${operation} p95 latency ${String(round2(measuredP95Ms))}ms vs baseline ${String(round2(baselineP95Ms))}ms (+${String(deltaPct)}%)`,\n body: [\n `Measured p95 latency regressed beyond the configured tolerance against a STATIC baseline.`,\n '',\n `- Component: \\`${component}\\``,\n `- Operation: \\`${operation}\\``,\n `- Measured p95: ${String(round2(measuredP95Ms))} ms`,\n `- Baseline p95: ${String(round2(baselineP95Ms))} ms (static/configured — not a rolling window)`,\n `- Tolerance: ${String(round2(tolerance * 100))}% (regression threshold ${String(round2(threshold))} ms)`,\n `- Delta: +${String(deltaPct)}% worse than baseline`,\n '',\n 'Surfaced as a candidate finding for human review. No fitness/governance score is mutated and no remediation is auto-applied.',\n ].join('\\n'),\n evidence: { observedValue: round2(measuredP95Ms), threshold: round2(threshold) },\n };\n}\n\n/**\n * Build a throughput-regression signal. Boundary is EXCLUSIVE: fires only when\n * `measuredThroughput < baselineThroughput * (1 - tolerance)` — exactly at the\n * threshold is NOT a regression (conservative).\n */\nfunction throughputRegressionSignal(\n component: string,\n operation: string,\n measuredThroughput: number,\n baselineThroughput: number,\n tolerance: number\n): ImprovementSignal | undefined {\n const threshold = baselineThroughput * (1 - tolerance);\n if (measuredThroughput >= threshold) return undefined;\n const deltaPct = pctWorse(measuredThroughput, baselineThroughput);\n return {\n category: 'perf-regression',\n signalKey: `perf-regression:throughput:${component}:${operation}`,\n severity: 'warning',\n title: `perf-regression: ${component}/${operation} throughput ${String(round2(measuredThroughput))} ops/s vs baseline ${String(round2(baselineThroughput))} ops/s (-${String(deltaPct)}%)`,\n body: [\n `Measured throughput regressed beyond the configured tolerance against a STATIC baseline.`,\n '',\n `- Component: \\`${component}\\``,\n `- Operation: \\`${operation}\\``,\n `- Measured throughput: ${String(round2(measuredThroughput))} ops/s`,\n `- Baseline throughput: ${String(round2(baselineThroughput))} ops/s (static/configured — not a rolling window)`,\n `- Tolerance: ${String(round2(tolerance * 100))}% (regression threshold ${String(round2(threshold))} ops/s)`,\n `- Delta: -${String(deltaPct)}% below baseline`,\n '',\n 'Surfaced as a candidate finding for human review. No fitness/governance score is mutated and no remediation is auto-applied.',\n ].join('\\n'),\n evidence: { observedValue: round2(measuredThroughput), threshold: round2(threshold) },\n };\n}\n\n/**\n * Map a benchmark suite result + a STATIC baseline map to `perf-regression`\n * signals. Pure and deterministic: same inputs → same output.\n *\n * For each operation, looks up `\"<component>::<operation>\"` in `baselines`:\n * - No entry → emit nothing (conservative; never invents a baseline).\n * - Latency: emit when measured p95 > baseline p95 * (1 + tolerance).\n * - Throughput: emit when measured throughput < baseline throughput * (1 - tolerance).\n * Latency and throughput are independent — an operation can emit both.\n *\n * @param result the measured benchmark suite (component + operations).\n * @param baselines the static, configured baseline map (never auto-derived).\n * @param tolerance fractional tolerance; defaults to\n * {@link DEFAULT_REGRESSION_TOLERANCE_FRACTION} (0.2 = 20%).\n */\nexport function detectPerfRegressionSignals(\n result: BenchmarkSuiteResult,\n baselines: PerfBaselineMap,\n tolerance: number = DEFAULT_REGRESSION_TOLERANCE_FRACTION\n): readonly ImprovementSignal[] {\n const signals: ImprovementSignal[] = [];\n for (const op of result.operations) {\n const baseline = baselines.get(baselineKey(result.component, op.operation));\n if (baseline === undefined) continue; // no configured baseline → no signal.\n if (baseline.baselineP95Ms !== undefined) {\n const sig = latencyRegressionSignal(\n result.component,\n op.operation,\n op.latency.p95,\n baseline.baselineP95Ms,\n tolerance\n );\n if (sig !== undefined) signals.push(sig);\n }\n if (baseline.baselineThroughput !== undefined) {\n const sig = throughputRegressionSignal(\n result.component,\n op.operation,\n op.throughput.opsPerSecond,\n baseline.baselineThroughput,\n tolerance\n );\n if (sig !== undefined) signals.push(sig);\n }\n }\n return signals;\n}\n","/**\n * Improvement-signal → remediation-task bridge (#3540, capability-loop increment 1).\n *\n * The \"safe plumbing\" half of the capability loop: turn the observability\n * signals `improvement_review` already detects (fitness decline, CLI-floor,\n * failure-category concentration, consensus rejection, self-eval findings) into\n * structured remediation {@link PipelineTask}s, surfaced for human review.\n *\n * SUGGEST-ONLY by construction: this is a pure mapping. It executes nothing,\n * files nothing, and auto-invokes no pipeline — the safety-critical auto-invoke\n * gate is a deliberately separate, later increment (still owner-gated). A\n * reviewer (or a future human-gated path) decides whether to route a task\n * through the dev-pipeline.\n *\n * @module mcp/tools/improvement-remediation\n */\n\nimport type { PipelineTask, PipelineRole } from '../../pipeline/dev-pipeline.js';\nimport type { ImprovementSignal, SignalCategory } from './improvement-review.js';\n\n/**\n * Which pipeline role should own a remediation, by signal category. The\n * dev-pipeline re-plans from research anyway, so this is the seed owner, not a\n * final assignment.\n */\nconst ROLE_BY_CATEGORY: Readonly<Record<SignalCategory, PipelineRole>> = {\n security: 'security',\n bug: 'coder',\n 'tech-debt': 'coder',\n routing: 'researcher',\n consensus: 'researcher',\n // #3852: tool-fitness candidates are deprecation/consolidation proposals —\n // a researcher owns the investigation seed (suggest-tier; the dev-pipeline\n // re-plans anyway). NEVER an autonomous removal.\n 'tool-fitness': 'researcher',\n // #3692/#3246: a perf regression vs a static baseline is a performance\n // investigation seed — a coder owns the diagnosis. Surfaced-only; the\n // dev-pipeline re-plans, nothing is auto-applied.\n 'perf-regression': 'coder',\n};\n\n/** Stable, dedup-friendly task id for a signal (mirrors the signalKey). */\nexport function remediationTaskId(signal: ImprovementSignal): string {\n return `improvement-${signal.signalKey}`;\n}\n\n/** Maps one improvement signal to a suggest-only remediation task. */\nexport function improvementSignalToTask(signal: ImprovementSignal): PipelineTask {\n return {\n id: remediationTaskId(signal),\n title: signal.title,\n description:\n `Auto-suggested remediation from improvement_review (#3540 — SUGGEST-ONLY, nothing executed). ` +\n `Category: ${signal.category}; severity: ${signal.severity}.\\n\\n${signal.body}\\n\\n` +\n `If accepted, route this through the dev-pipeline (research → plan → vote → implement → QA → ` +\n `security gate). Auto-invocation is a separate, owner-gated step.`,\n assignedTo: ROLE_BY_CATEGORY[signal.category],\n status: 'pending',\n };\n}\n\n/**\n * Maps detected improvement signals to remediation tasks for review. Preserves\n * input order (signals arrive severity-sorted) and dedups by task id against\n * `existingTaskIds` when provided.\n */\nexport function improvementSignalsToTasks(\n signals: readonly ImprovementSignal[],\n existingTaskIds?: ReadonlySet<string>\n): PipelineTask[] {\n const tasks: PipelineTask[] = [];\n for (const signal of signals) {\n const task = improvementSignalToTask(signal);\n if (existingTaskIds?.has(task.id) === true) continue;\n tasks.push(task);\n }\n return tasks;\n}\n","/**\n * Shadow-mode auto-remediation selector (#3540 increment 2a / #3611).\n *\n * The safe, zero-blast-radius first step of the capability loop's auto-invoke\n * gate. For each remediation task derived from improvement_review signals\n * (#3609), it records the decision the *future* gate WOULD make — \"would this\n * signal be auto-routed through the dev-pipeline?\" — WITHOUT executing anything.\n * No pipeline is invoked, no PR opened, no issue filed.\n *\n * This accumulates the selection data that #3612 (the quantified shadow→enforce\n * exit criterion) evaluates before any enforcement (#3618) is ever enabled —\n * mirroring the learned-selection shadow tier (#3551) and tune-loop (#3147).\n *\n * The one hard exclusion encoded here is security-category signals (always\n * human-gated, never auto-remediated) — the fail-closed classifier hardening is\n * #3615; the rate-limit / Rule-of-Two / runaway bounds land with their own\n * issues. This module decides nothing operational: it only observes.\n *\n * @module mcp/tools/improvement-remediation-shadow\n */\n\nimport { z } from 'zod';\n\nimport { getTimeProvider } from '../../core/index.js';\nimport type { ImprovementSignal } from './improvement-review.js';\nimport { remediationTaskId } from './improvement-remediation.js';\nimport { SECURITY_KEYWORDS } from '../gateway/gateway-keywords.js';\nimport { JsonlStore } from '../../config/jsonl-store.js';\nimport { nexusDataPath } from '../../config/nexus-data-dir.js';\nimport { scanForSecrets, describeSecretFindings } from './diff-secret-scan.js';\n\n/**\n * Fail-closed security classification (#3540 inc.2e / #3615). The hard\n * exclusion \"security signals are always human-gated\" only holds if\n * classification is correct — a security issue mislabeled by a detector (e.g. as\n * `bug` or `routing`) would otherwise silently bypass the gate. So we treat a\n * signal as security if EITHER its declared category is `security` OR any\n * security keyword appears in its key/title/body. Uncertain → security →\n * human-gated. This is intentionally over-inclusive (false positives only cost a\n * human review; a false negative auto-remediates a security issue unreviewed),\n * and is reused by the future enforce path (#3618) so both decide identically.\n */\nexport function isSecuritySignal(signal: ImprovementSignal): boolean {\n if (signal.category === 'security') return true;\n const haystack = `${signal.signalKey}\\n${signal.title}\\n${signal.body}`.toLowerCase();\n return SECURITY_KEYWORDS.some((kw) => haystack.includes(kw));\n}\n\n/** One shadow decision: would the gate auto-route this remediation? (Logged only.) */\nexport interface RemediationShadowRecord {\n readonly timestamp: string;\n /** The improvement signal's stable key. */\n readonly signalKey: string;\n /** The remediation task id (from the #3609 bridge). */\n readonly taskId: string;\n readonly category: ImprovementSignal['category'];\n readonly severity: ImprovementSignal['severity'];\n /** Whether the gate WOULD auto-route this to the dev-pipeline (shadow — not executed). */\n readonly wouldAutoRemediate: boolean;\n /** Human-readable explanation of the shadow decision. */\n readonly reason: string;\n}\n\n/**\n * The shadow decision for one signal. Security-category signals are always\n * human-gated (never auto-remediated), even in shadow — so the accumulated data\n * reflects the real gate's hard exclusion. Everything else is a shadow\n * would-remediate=true (no execution happens regardless).\n */\nexport function evaluateRemediationShadow(signal: ImprovementSignal): RemediationShadowRecord {\n // Fail-closed (#3615): category==='security' OR any security keyword → gate.\n const isSecurity = isSecuritySignal(signal);\n const gatedByKeyword = isSecurity && signal.category !== 'security';\n return {\n timestamp: new Date(getTimeProvider().now()).toISOString(),\n signalKey: signal.signalKey,\n taskId: remediationTaskId(signal),\n category: signal.category,\n severity: signal.severity,\n wouldAutoRemediate: !isSecurity,\n reason: gatedByKeyword\n ? `security-related (keyword match, declared category '${signal.category}') — fail-closed human-gated`\n : isSecurity\n ? 'security-category — always human-gated, never auto-remediated'\n : 'shadow: would route to the dev-pipeline for remediation (not executed)',\n };\n}\n\n/** Offline-evaluation summary over shadow records (consumed by #3612). */\nexport interface RemediationShadowSummary {\n readonly total: number;\n /** How many the gate would have auto-routed (non-security). */\n readonly wouldAutoRemediate: number;\n /** How many were held for a human (security-category). */\n readonly humanGated: number;\n readonly byCategory: Readonly<Record<string, number>>;\n}\n\n/** A sink that records every shadow decision. Must not throw. */\nexport interface RemediationShadowSink {\n record(record: RemediationShadowRecord): void;\n}\n\n/** A {@link RemediationShadowSink} that also exposes its buffered records. */\nexport interface IRecordingRemediationShadowSink extends RemediationShadowSink {\n getRecords(): readonly RemediationShadowRecord[];\n}\n\n/** Default cap for the in-memory recording sink (matches the other shadow sinks). */\nconst DEFAULT_MAX_RECORDS = 200;\n\n/** Creates an in-memory shadow sink with a bounded buffer (oldest evicted). */\nexport function createRemediationShadowSink(\n maxRecords = DEFAULT_MAX_RECORDS\n): IRecordingRemediationShadowSink {\n const records: RemediationShadowRecord[] = [];\n return {\n record(record: RemediationShadowRecord): void {\n records.push(record);\n if (records.length > maxRecords) {\n records.splice(0, records.length - maxRecords);\n }\n },\n getRecords(): readonly RemediationShadowRecord[] {\n return records;\n },\n };\n}\n\n/** Summarizes shadow records for offline policy evaluation (#3612). */\nexport function summarizeRemediationShadow(\n records: readonly RemediationShadowRecord[]\n): RemediationShadowSummary {\n const byCategory: Record<string, number> = {};\n let wouldAutoRemediate = 0;\n for (const r of records) {\n if (r.wouldAutoRemediate) wouldAutoRemediate++;\n byCategory[r.category] = (byCategory[r.category] ?? 0) + 1;\n }\n return {\n total: records.length,\n wouldAutoRemediate,\n humanGated: records.length - wouldAutoRemediate,\n byCategory,\n };\n}\n\nlet singletonSink: IRecordingRemediationShadowSink | undefined;\n\n/** Process-scoped shadow sink — accumulates would-remediate decisions across runs. */\nexport function getRemediationShadowSink(): IRecordingRemediationShadowSink {\n singletonSink ??= createRemediationShadowSink();\n return singletonSink;\n}\n\n/**\n * Records shadow would-remediate decisions for a set of detected signals — the\n * default-on, zero-blast-radius observability path (#3611). Returns the records\n * it logged. Executes nothing; never throws is the caller's contract (wrap in\n * try/catch at the call site so observability can't break the tool).\n *\n * `tasks` is accepted to assert the bridge produced a task per non-excluded\n * signal, keeping the shadow log aligned with what would actually be routed.\n */\nexport function recordRemediationShadow(\n signals: readonly ImprovementSignal[],\n sink: RemediationShadowSink = getRemediationShadowSink()\n): readonly RemediationShadowRecord[] {\n const records = signals.map(evaluateRemediationShadow);\n for (const record of records) sink.record(record);\n return records;\n}\n\n// ============================================================================\n// Durable audit-mode SOAK sink (#3762) — the enforce-decision-gate evidence.\n// ============================================================================\n\n/**\n * Verdict tally from a consensus vote (approved/rejected + the approval %).\n * Mirrors {@link AutoRemediationDeps.vote}'s return shape (#3653).\n */\nexport const SoakVoteOutcomeSchema = z.object({\n approved: z.boolean(),\n /** Approval percentage at vote time, 0–100 (the consensus tally). */\n approvalPercentage: z.number(),\n});\nexport type SoakVoteOutcome = z.infer<typeof SoakVoteOutcomeSchema>;\n\n/**\n * One durable record of what AUDIT mode decided for a single signal — the\n * cross-run soak evidence the enforce-by-default decision gate consumes (#3540\n * / #3762). Captures the vote/plan outcome with ZERO writes to the repo.\n *\n * Free-text fields (`reason`, `dryRunResult`) are secret-scrubbed before\n * persistence (see {@link scrubSoakRecord}) — persisted evidence must never\n * carry a secret (#3669 / Security condition).\n */\nexport const RemediationSoakRecordSchema = z.object({\n /** ISO-8601 capture time. */\n timestamp: z.string(),\n /** The improvement signal's stable key. */\n signalKey: z.string(),\n /** The signal's category. */\n category: z.string(),\n /** The classified remediation priority (p0–p4). */\n priority: z.string(),\n /** The signal's declared severity. */\n severity: z.string(),\n /** Vote outcome (approved/rejected + tally), undefined if the signal never reached a vote. */\n voteOutcome: SoakVoteOutcomeSchema.optional(),\n /** Number of plan steps research produced (0 if research/plan failed). */\n planStepCount: z.number(),\n /** p0 dry-run result detail (scrubbed); undefined for non-p0 or when no dry-run ran. */\n dryRunResult: z.string().optional(),\n /** Human-readable verdict reason (scrubbed). */\n reason: z.string(),\n});\nexport type RemediationSoakRecord = z.infer<typeof RemediationSoakRecordSchema>;\n\n/**\n * Retention cap for the durable soak sink. Generous enough to accumulate a real\n * multi-week soak while bounding disk usage (oldest-evicted, #3762 Contrarian\n * condition). Override is intentionally NOT an env var — a fixed bound keeps the\n * evidence file size predictable for the readiness collector (#3764).\n */\nexport const SOAK_MAX_RECORDS = 10_000;\n\n/** JSONL file under NEXUS_DATA_DIR holding the durable audit-mode soak evidence. */\nexport function getRemediationSoakFile(): string {\n return nexusDataPath('learning', 'remediation-soak.jsonl');\n}\n\n/**\n * Redact any secret in a soak record's free-text fields before it is persisted.\n * On a hit the value is replaced with a value-free marker naming the matched\n * pattern(s) — the record stays useful as evidence without leaking the secret.\n */\nexport function scrubSoakRecord(record: RemediationSoakRecord): RemediationSoakRecord {\n const scrub = (text: string): string => {\n const result = scanForSecrets(text);\n if (result.clean) return text;\n return `[redacted: ${describeSecretFindings(result)}]`;\n };\n const scrubbed: RemediationSoakRecord = {\n ...record,\n reason: scrub(record.reason),\n ...(record.dryRunResult !== undefined ? { dryRunResult: scrub(record.dryRunResult) } : {}),\n };\n return scrubbed;\n}\n\n/** Durable sink for audit-mode soak records. Scrubs + persists; never throws. */\nexport interface RemediationSoakSink {\n record(record: RemediationSoakRecord): void;\n}\n\n/** A {@link RemediationSoakSink} that also exposes its persisted records. */\nexport interface IRecordingRemediationSoakSink extends RemediationSoakSink {\n getRecords(): readonly RemediationSoakRecord[];\n}\n\n/**\n * Create a durable soak sink backed by an append-only JSONL file (reuses the\n * shared {@link JsonlStore} primitive — hydrate-on-construct, append-on-write,\n * Zod-validate each line, oldest-eviction at {@link SOAK_MAX_RECORDS}).\n * Records are secret-scrubbed before they hit disk.\n */\nexport function createRemediationSoakSink(\n filePath: string = getRemediationSoakFile(),\n maxRecords: number = SOAK_MAX_RECORDS\n): IRecordingRemediationSoakSink {\n const store = new JsonlStore<RemediationSoakRecord>({\n filePath,\n schema: RemediationSoakRecordSchema,\n maxRecords,\n component: 'RemediationSoakSink',\n });\n return {\n record(record: RemediationSoakRecord): void {\n store.append(scrubSoakRecord(record));\n },\n getRecords(): readonly RemediationSoakRecord[] {\n return store.all();\n },\n };\n}\n\nlet soakSingleton: IRecordingRemediationSoakSink | undefined;\n\n/** Process-wide durable soak sink (lazily constructed, hydrates from disk). */\nexport function getRemediationSoakSink(): IRecordingRemediationSoakSink {\n soakSingleton ??= createRemediationSoakSink();\n return soakSingleton;\n}\n\n/** Test helper — drops the cached singleton so a fresh NEXUS_DATA_DIR is picked up. */\nexport function _resetRemediationSoakSinkForTests(): void {\n soakSingleton = undefined;\n}\n\n/**\n * Aggregate summary over persisted soak records — the read surface the #3764\n * readiness collector (and a human) consume. Reports counts by verdict, the\n * approval rate over signals that reached a vote, and per-category/per-priority\n * breakdowns. Pure over its input; does no I/O.\n */\nexport interface RemediationSoakSummary {\n /** Total soak records. */\n readonly total: number;\n /** How many reached a consensus vote. */\n readonly voted: number;\n /** Approved votes. */\n readonly approved: number;\n /** Rejected votes (voted − approved). */\n readonly rejected: number;\n /** approved / voted, or 0 when nothing was voted. */\n readonly approvalRate: number;\n /** How many p0 dry-runs were captured. */\n readonly dryRunsCaptured: number;\n readonly byCategory: Readonly<Record<string, number>>;\n readonly byPriority: Readonly<Record<string, number>>;\n /** ISO timestamp of the first / last record, if any. */\n readonly firstTimestamp?: string;\n readonly lastTimestamp?: string;\n}\n\n/** Mutable accumulator for the soak summary tallies. */\ninterface SoakTally {\n byCategory: Record<string, number>;\n byPriority: Record<string, number>;\n voted: number;\n approved: number;\n dryRunsCaptured: number;\n}\n\n/** Fold one record into the running tally. */\nfunction tallySoakRecord(t: SoakTally, r: RemediationSoakRecord): void {\n t.byCategory[r.category] = (t.byCategory[r.category] ?? 0) + 1;\n t.byPriority[r.priority] = (t.byPriority[r.priority] ?? 0) + 1;\n if (r.voteOutcome !== undefined) {\n t.voted++;\n if (r.voteOutcome.approved) t.approved++;\n }\n if (r.dryRunResult !== undefined) t.dryRunsCaptured++;\n}\n\n/** Summarize soak records for the readiness gate (#3764). */\nexport function summarizeRemediationSoak(\n records: readonly RemediationSoakRecord[]\n): RemediationSoakSummary {\n const t: SoakTally = {\n byCategory: {},\n byPriority: {},\n voted: 0,\n approved: 0,\n dryRunsCaptured: 0,\n };\n for (const r of records) tallySoakRecord(t, r);\n const first = records[0]?.timestamp;\n const last = records[records.length - 1]?.timestamp;\n return {\n total: records.length,\n voted: t.voted,\n approved: t.approved,\n rejected: t.voted - t.approved,\n approvalRate: t.voted === 0 ? 0 : t.approved / t.voted,\n dryRunsCaptured: t.dryRunsCaptured,\n byCategory: t.byCategory,\n byPriority: t.byPriority,\n ...(first !== undefined ? { firstTimestamp: first } : {}),\n ...(last !== undefined ? { lastTimestamp: last } : {}),\n };\n}\n\n/**\n * Conservative sanity check on a soak record's `signalKey` (#3932). Real keys\n * are emitted by `improvement_review` and always carry the `category:detail`\n * shape (e.g. `routing:cli-floor:codex:docs`, `bug:failure-concentration:auth`,\n * `tech-debt:fitness-below-floor`): at least one `:` with a non-empty segment on\n * each side. Synthetic test fixtures that leaked into the durable file used bare\n * single tokens (`a`, `b`, `x`) with no colon. Rejecting those keeps obviously-\n * junk records from inflating the readiness `volume` criterion.\n *\n * Intentionally permissive: it requires only the colon-delimited shape, NOT a\n * known category enum — a legitimate future category must never be dropped. Any\n * real key passes; only structureless tokens fail.\n */\nexport function isPlausibleSoakSignalKey(signalKey: string): boolean {\n const colon = signalKey.indexOf(':');\n if (colon <= 0) return false; // no colon, or empty category before it\n return colon < signalKey.length - 1; // a non-empty detail follows the colon\n}\n\n/**\n * Drop obviously-synthetic soak records before they reach the readiness gate\n * (#3932 defense-in-depth). Conservative: only records whose `signalKey` lacks\n * the real `category:detail` shape are discarded — see {@link isPlausibleSoakSignalKey}.\n */\nexport function filterPlausibleSoakRecords(\n records: readonly RemediationSoakRecord[]\n): readonly RemediationSoakRecord[] {\n return records.filter((r) => isPlausibleSoakSignalKey(r.signalKey));\n}\n\n/**\n * Read + summarize the durable soak evidence from disk (convenience for #3764).\n * Filters out structurally-implausible records first (#3932) so junk fixtures\n * that may have leaked into the file can't inflate the readiness volume count.\n */\nexport function readRemediationSoakSummary(\n sink: IRecordingRemediationSoakSink = getRemediationSoakSink()\n): RemediationSoakSummary {\n return summarizeRemediationSoak(filterPlausibleSoakRecords(sink.getRecords()));\n}\n\n// ============================================================================\n// Audit-branch wiring (#3762) — turn per-step audit events into soak records.\n// ============================================================================\n\n/** The per-step audit event shape emitted by runAutoRemediation. */\nexport interface SoakAuditEvent {\n readonly step: string;\n readonly signalKey?: string;\n readonly detail: string;\n}\n\n/** Look up a signal's category/priority/severity for the soak record. */\nexport interface SoakSignalMeta {\n readonly category: string;\n readonly priority: string;\n readonly severity: string;\n}\n\n/**\n * An audit collector that turns the discrete per-step audit events\n * (`plan` / `vote` / `dry-run` / `skip` / …) emitted by `runAutoRemediation`\n * into one durable {@link RemediationSoakRecord} per signal, then persists them\n * via the durable sink on {@link flush}. This is the bridge that makes AUDIT\n * mode produce queryable, cross-run evidence instead of only `logger.info`.\n *\n * It accumulates by `signalKey` so a signal's plan-step count, vote tally, and\n * dry-run result land in the SAME record. Records are flushed (persisted) at the\n * end of the run. Never throws — observability must not break remediation.\n */\nexport interface RemediationSoakCollector {\n /** Feed one audit event (call from the wrapped `audit` callback). */\n observe(event: SoakAuditEvent): void;\n /** Persist all accumulated per-signal records to the durable sink. */\n flush(): readonly RemediationSoakRecord[];\n}\n\n/** Mutable per-signal accumulator. */\ninterface SoakDraft {\n signalKey: string;\n planStepCount: number;\n voteOutcome?: SoakVoteOutcome;\n dryRunResult?: string;\n reason: string;\n}\n\n/** Parse `\"unanimous: approved (100%)\"` → vote outcome. Returns undefined if unparseable. */\nfunction parseVoteDetail(detail: string): SoakVoteOutcome | undefined {\n const approved = /\\bapproved\\b/.test(detail);\n const rejected = /\\brejected\\b/.test(detail);\n if (!approved && !rejected) return undefined;\n const pct = /(\\d+(?:\\.\\d+)?)%/.exec(detail);\n return {\n approved,\n approvalPercentage: pct?.[1] !== undefined ? Number(pct[1]) : approved ? 100 : 0,\n };\n}\n\n/** Steps whose detail is a terminal verdict reason for the signal. */\nconst SOAK_TERMINAL_REASON_STEPS: ReadonlySet<string> = new Set([\n 'skip',\n 'research-failed',\n 'protected-path',\n]);\n\n/** Fold one audit event into the per-signal draft (mutates `d`). */\nfunction applySoakEvent(d: SoakDraft, event: SoakAuditEvent): void {\n if (event.step === 'plan') {\n const n = /(\\d+)\\s*steps?/.exec(event.detail);\n d.planStepCount = n?.[1] !== undefined ? Number(n[1]) : 0;\n if (d.reason === '') d.reason = 'plan produced';\n return;\n }\n if (event.step === 'vote') {\n const outcome = parseVoteDetail(event.detail);\n if (outcome !== undefined) d.voteOutcome = outcome;\n d.reason = event.detail;\n return;\n }\n if (event.step === 'dry-run') {\n d.dryRunResult = event.detail;\n return;\n }\n // start / abort / pr-opened are not soak verdict inputs and are ignored.\n if (SOAK_TERMINAL_REASON_STEPS.has(event.step)) d.reason = event.detail;\n}\n\n/** Project a finished draft + its signal meta into a durable soak record. */\nfunction draftToSoakRecord(\n d: SoakDraft,\n meta: SoakSignalMeta | undefined,\n timestamp: string\n): RemediationSoakRecord {\n return {\n timestamp,\n signalKey: d.signalKey,\n category: meta?.category ?? 'unknown',\n priority: meta?.priority ?? 'unknown',\n severity: meta?.severity ?? 'unknown',\n ...(d.voteOutcome !== undefined ? { voteOutcome: d.voteOutcome } : {}),\n planStepCount: d.planStepCount,\n ...(d.dryRunResult !== undefined ? { dryRunResult: d.dryRunResult } : {}),\n reason: d.reason === '' ? 'no verdict recorded' : d.reason,\n };\n}\n\n/**\n * Build a soak collector. `metaFor` resolves a signal's category/priority/severity\n * (the audit events only carry the signalKey + detail). `sink` defaults to the\n * durable singleton; tests inject an isolated one.\n */\nexport function createRemediationSoakCollector(\n metaFor: (signalKey: string) => SoakSignalMeta | undefined,\n sink: IRecordingRemediationSoakSink = getRemediationSoakSink()\n): RemediationSoakCollector {\n const drafts = new Map<string, SoakDraft>();\n const draftFor = (signalKey: string): SoakDraft => {\n let d = drafts.get(signalKey);\n if (d === undefined) {\n d = { signalKey, planStepCount: 0, reason: '' };\n drafts.set(signalKey, d);\n }\n return d;\n };\n return {\n observe(event: SoakAuditEvent): void {\n if (event.signalKey === undefined) return; // run-level (start/abort) — not per-signal.\n applySoakEvent(draftFor(event.signalKey), event);\n },\n flush(): readonly RemediationSoakRecord[] {\n const ts = new Date(getTimeProvider().now()).toISOString();\n const out: RemediationSoakRecord[] = [];\n for (const d of drafts.values()) {\n const record = draftToSoakRecord(d, metaFor(d.signalKey), ts);\n sink.record(record);\n out.push(record);\n }\n drafts.clear();\n return out;\n },\n };\n}\n","/**\n * Pre-push secret scan for auto-remediation diffs (#3540 phase 3 / #3669).\n *\n * The #3618/#3648 consensus votes flagged THE gap the merge-time safeguards miss:\n * `gh pr create` PUBLISHES the branch, so a secret a remediation writes into the\n * diff is leaked the instant it's pushed — before never-auto-merge / CODEOWNERS /\n * the breaker ever fire, and irreversibly in git history. So the auto-remediation\n * implement adapters MUST scan the staged content BEFORE push and fail closed.\n *\n * This is an in-tree, dependency-free regex scanner (gitleaks/trufflehog can be\n * layered on top later). Fail-closed: any match → not clean → the adapter aborts\n * the push.\n *\n * @module mcp/tools/diff-secret-scan\n */\n\n/** A known secret shape. */\ninterface SecretPattern {\n readonly name: string;\n readonly re: RegExp;\n}\n\n/** High-signal secret patterns (kept conservative to limit false positives). */\nconst SECRET_PATTERNS: readonly SecretPattern[] = [\n { name: 'private-key-block', re: /-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/ },\n { name: 'aws-access-key-id', re: /\\bAKIA[0-9A-Z]{16}\\b/ },\n { name: 'github-token', re: /\\bgh[pousr]_[A-Za-z0-9]{36,}\\b/ },\n { name: 'slack-token', re: /\\bxox[baprs]-[A-Za-z0-9-]{10,}\\b/ },\n { name: 'google-api-key', re: /\\bAIza[0-9A-Za-z_-]{35}\\b/ },\n { name: 'openai-key', re: /\\bsk-[A-Za-z0-9]{32,}\\b/ },\n // Newer OpenAI key families: project/service-account/admin keys carry a\n // `sk-proj-`/`sk-svcacct-`/`sk-admin-` prefix and base64url bodies (with - and\n // _), so the classic class above breaks at the first hyphen (#3752).\n { name: 'openai-key', re: /\\bsk-(?:proj|svcacct|admin)-[A-Za-z0-9_-]{20,}\\b/ },\n { name: 'anthropic-key', re: /\\bsk-ant-[A-Za-z0-9_-]{20,}\\b/ },\n { name: 'jwt', re: /\\beyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\b/ },\n // Generic `secret/token/password/api_key = \"long-value\"` assignments. The value\n // class includes `=` so base64 values with padding (…==) still match (#3752).\n {\n name: 'generic-credential-assignment',\n re: /(?:api[_-]?key|secret|token|password|passwd|credential)\\s*[:=]\\s*[\"'][A-Za-z0-9/+_=-]{16,}[\"']/i,\n },\n];\n\n/** One secret finding (the matched pattern + a redacted locator). */\nexport interface SecretFinding {\n readonly pattern: string;\n /** 1-based line number within the scanned text. */\n readonly line: number;\n}\n\n/** Scan result. `clean` is true only when there are zero findings. */\nexport interface SecretScanResult {\n readonly clean: boolean;\n readonly findings: readonly SecretFinding[];\n}\n\n/**\n * Scan text (e.g. a unified diff or a file's contents) for secrets. Fail-closed:\n * the caller treats `clean === false` as \"do not push\". Findings report the\n * pattern name + line only — never the secret value.\n *\n * @remarks Fail-closed: any single pattern match flips `clean` to `false`.\n */\nexport function scanForSecrets(text: string): SecretScanResult {\n const findings: SecretFinding[] = [];\n const lines = text.split('\\n');\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? '';\n for (const { name, re } of SECRET_PATTERNS) {\n if (re.test(line)) findings.push({ pattern: name, line: i + 1 });\n }\n }\n return { clean: findings.length === 0, findings };\n}\n\n/** Human-readable, value-free summary of a scan result. */\nexport function describeSecretFindings(result: SecretScanResult): string {\n if (result.clean) return 'no secrets detected';\n return result.findings.map((f) => `${f.pattern}@L${String(f.line)}`).join(', ');\n}\n","/**\n * Priority → consensus-rigor policy for autonomous remediation (#3540 phase 3 / #3653).\n *\n * Owner-directed, consensus-ratified (higher_order 7/7): every surfaced gap/idea/\n * signal is tagged p0–p4 (priority = severity × blast-radius), and the priority\n * selects the consensus rigor required before the loop may auto-remediate it.\n * Higher blast-radius ⇒ stricter algorithm + (for p0) a mandatory dry-run; the\n * lowest tier is file-only (backlog, never auto-remediated).\n *\n * This is the pure policy core — the auto-filer (labels), the enforce\n * orchestrator (gating), and the issue-triage surface all read from here so the\n * mapping has a single authoritative representation (DRY).\n *\n * @module mcp/tools/remediation-priority\n */\n\nimport type { ConsensusAlgorithm } from '../../consensus/types-core.js';\nimport type { ImprovementSignal } from './improvement-review.js';\nimport { isSecuritySignal } from './improvement-remediation-shadow.js';\n\n/** Priority tiers, p0 (most critical) → p4 (trivial/idea). */\nexport type RemediationPriority = 'p0' | 'p1' | 'p2' | 'p3' | 'p4';\n\n/** All tiers, strictest first. */\nexport const REMEDIATION_PRIORITIES: readonly RemediationPriority[] = [\n 'p0',\n 'p1',\n 'p2',\n 'p3',\n 'p4',\n];\n\n/** The GitHub label applied to an auto-filed issue at a given priority. */\nexport function priorityLabel(priority: RemediationPriority): string {\n return priority; // labels are literally `p0`…`p4`\n}\n\n/** The consensus rigor required before auto-remediating a tier. */\nexport interface ConsensusRequirement {\n /** Whether the tier is eligible for auto-remediation at all (p4 = file-only). */\n readonly autoRemediate: boolean;\n /** Consensus algorithm to require (undefined when not auto-remediated). */\n readonly algorithm?: ConsensusAlgorithm;\n /** p0 additionally requires a green audit-mode dry-run before a PR is opened. */\n readonly requiresDryRun: boolean;\n}\n\n/**\n * Priority → consensus requirement. p0 is unanimous + dry-run (security/breaking);\n * tiers relax down to file-only at p4. Uses the canonical {@link ConsensusAlgorithm}\n * values so the enforce path passes them straight to `consensus_vote`.\n */\nconst REQUIREMENT_BY_PRIORITY: Readonly<Record<RemediationPriority, ConsensusRequirement>> = {\n p0: { autoRemediate: true, algorithm: 'unanimous', requiresDryRun: true },\n p1: { autoRemediate: true, algorithm: 'supermajority', requiresDryRun: false },\n p2: { autoRemediate: true, algorithm: 'higher_order', requiresDryRun: false },\n p3: { autoRemediate: true, algorithm: 'simple_majority', requiresDryRun: false },\n p4: { autoRemediate: false, requiresDryRun: false },\n};\n\n/** Resolve the consensus requirement for a priority tier. */\nexport function consensusFor(priority: RemediationPriority): ConsensusRequirement {\n return REQUIREMENT_BY_PRIORITY[priority];\n}\n\n/**\n * Classify an improvement signal's priority. Security is ALWAYS p0 (fail-closed,\n * via {@link isSecuritySignal} which is itself keyword-fail-closed, #3615);\n * otherwise severity drives the tier. Returns the strictest applicable tier.\n */\nexport function classifySignalPriority(signal: ImprovementSignal): RemediationPriority {\n if (isSecuritySignal(signal)) return 'p0';\n switch (signal.severity) {\n case 'critical':\n return 'p0';\n case 'warning':\n return 'p2';\n default:\n return 'p3';\n }\n}\n"],"mappings":"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","names":["execFile","promisify","z","description","z","z","execFileAsync","promisify","execFile","z"]}
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  loadPapersRegistry
3
- } from "./chunk-B26FGLIJ.js";
3
+ } from "./chunk-ZHCEOIEQ.js";
4
4
  import {
5
5
  getErrorMessage
6
- } from "./chunk-DBDWMHUL.js";
6
+ } from "./chunk-OCJEYHUQ.js";
7
7
 
8
8
  // src/cli/research-helpers-synthesize.ts
9
9
  import { z } from "zod";
@@ -876,4 +876,4 @@ export {
876
876
  AttributedInsightSchema,
877
877
  synthesizeResearch
878
878
  };
879
- //# sourceMappingURL=chunk-UDB5NHJI.js.map
879
+ //# sourceMappingURL=chunk-4GVPON4W.js.map
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  resolveToken
3
- } from "./chunk-MY52DFXC.js";
3
+ } from "./chunk-FHFEC2XM.js";
4
4
  import {
5
5
  REGISTRY_PATH,
6
6
  getProjectRoot,
7
7
  loadPapersRegistry,
8
8
  loadTechniquesRegistry,
9
9
  savePapersRegistry
10
- } from "./chunk-B26FGLIJ.js";
11
- import {
12
- getToolMemory
13
- } from "./chunk-33MFMXBQ.js";
10
+ } from "./chunk-ZHCEOIEQ.js";
14
11
  import {
15
12
  resolveInsideRoot
16
13
  } from "./chunk-NUBSJGQZ.js";
14
+ import {
15
+ getToolMemory
16
+ } from "./chunk-ESP6U3LW.js";
17
17
  import {
18
18
  capitalizeWords
19
19
  } from "./chunk-6T3EPABN.js";
@@ -27,11 +27,11 @@ import {
27
27
  getOutcomeStore,
28
28
  getTimeProvider,
29
29
  registerPersistentDistillerFactory
30
- } from "./chunk-DBDWMHUL.js";
30
+ } from "./chunk-OCJEYHUQ.js";
31
31
  import {
32
32
  ensureLearningDir,
33
33
  getRulesFile
34
- } from "./chunk-GZ4NF4ZW.js";
34
+ } from "./chunk-5SXGPX34.js";
35
35
 
36
36
  // src/learning/strategy-distiller-persistence.ts
37
37
  import { writeFileSync, readFileSync, renameSync, unlinkSync, existsSync } from "fs";
@@ -2686,4 +2686,4 @@ export {
2686
2686
  summarizeContextForPrompt,
2687
2687
  getContextPromptPrefix
2688
2688
  };
2689
- //# sourceMappingURL=chunk-QZUT22LP.js.map
2689
+ //# sourceMappingURL=chunk-5546JU53.js.map