nexus-agents 2.133.0 → 2.135.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 (133) hide show
  1. package/dist/{child-mcp-config-R67B2KM6.js → child-mcp-config-RIEZRHWO.js} +3 -3
  2. package/dist/{chunk-RLYXX3FQ.js → chunk-2QTDOKWV.js} +2 -2
  3. package/dist/{chunk-K5WBFAR4.js → chunk-3IT473PY.js} +4 -4
  4. package/dist/{chunk-J435FU54.js → chunk-4L4VXVKC.js} +4 -4
  5. package/dist/{chunk-WHZD2W6Q.js → chunk-4NANSSKX.js} +2 -2
  6. package/dist/{chunk-NZGNOXXW.js → chunk-52N3NGEY.js} +2 -2
  7. package/dist/{chunk-EFDXX5MC.js → chunk-5MWNLEU2.js} +3 -3
  8. package/dist/{chunk-ECDJM6UB.js → chunk-BGGX3BXC.js} +2 -2
  9. package/dist/{chunk-2CLFX73Y.js → chunk-C46YFMFO.js} +2 -2
  10. package/dist/{chunk-CI5KGCX5.js → chunk-C4GDV57D.js} +3 -3
  11. package/dist/{chunk-S4U3Z6ZS.js → chunk-C5FWXNAR.js} +6 -6
  12. package/dist/{chunk-QJIHSQZX.js → chunk-CBJN5MYW.js} +72 -16
  13. package/dist/chunk-CBJN5MYW.js.map +1 -0
  14. package/dist/{chunk-TGGR6ST5.js → chunk-DXVQ6VFB.js} +3 -3
  15. package/dist/{chunk-PM63X3QG.js → chunk-FGQL4LZP.js} +3 -3
  16. package/dist/{chunk-DETYVPZO.js → chunk-FNYTCR6R.js} +6 -6
  17. package/dist/{chunk-QLRH6KOT.js → chunk-GM5F2FO5.js} +2 -2
  18. package/dist/{chunk-RUSP5PJR.js → chunk-GZ4NF4ZW.js} +5 -1
  19. package/dist/{chunk-RUSP5PJR.js.map → chunk-GZ4NF4ZW.js.map} +1 -1
  20. package/dist/{chunk-7BONPRR2.js → chunk-HDBV64A3.js} +2 -2
  21. package/dist/{chunk-ZTRBMKXK.js → chunk-HGYJLSLL.js} +2 -2
  22. package/dist/{chunk-XIFOAZ5B.js → chunk-ILH5TZAX.js} +4 -4
  23. package/dist/{chunk-GET2MTLW.js → chunk-JA3SDBVY.js} +2 -2
  24. package/dist/{chunk-HGUO36KW.js → chunk-JWWCNN76.js} +8 -8
  25. package/dist/{chunk-VZCQRLXT.js → chunk-K5O7SSOH.js} +7 -7
  26. package/dist/{chunk-ZVBGZBW5.js → chunk-KAIRRC5R.js} +226 -25
  27. package/dist/chunk-KAIRRC5R.js.map +1 -0
  28. package/dist/{chunk-4CVITS5D.js → chunk-ME4DQ6BI.js} +10 -10
  29. package/dist/chunk-ME4DQ6BI.js.map +1 -0
  30. package/dist/{chunk-4CLBJ2NA.js → chunk-MREIJMH7.js} +3 -3
  31. package/dist/{chunk-FKTLAPXJ.js → chunk-OQZQITVU.js} +3 -3
  32. package/dist/{chunk-RJEP2AZW.js → chunk-PZ3MGLJU.js} +175 -118
  33. package/dist/chunk-PZ3MGLJU.js.map +1 -0
  34. package/dist/{chunk-QMCHVYZB.js → chunk-QX2Y5QWO.js} +2 -2
  35. package/dist/{chunk-4DLHM6LI.js → chunk-SMRXY5ZN.js} +2 -2
  36. package/dist/{chunk-27DRQWON.js → chunk-T77RGBUF.js} +4 -4
  37. package/dist/{chunk-ZQEQVCIU.js → chunk-V6XZFDFR.js} +2 -2
  38. package/dist/{chunk-E4IYX7LD.js → chunk-WRP5COST.js} +2 -2
  39. package/dist/{chunk-RAWF4JOT.js → chunk-XM3OQXN5.js} +7 -7
  40. package/dist/{chunk-GYDO2WOR.js → chunk-ZVIBVJBI.js} +5 -5
  41. package/dist/{cli-circuit-breaker-J6UFONNE.js → cli-circuit-breaker-QONQNI3B.js} +5 -5
  42. package/dist/cli.js +844 -155
  43. package/dist/cli.js.map +1 -1
  44. package/dist/{composite-router-HQUSCJO4.js → composite-router-DU22RBNQ.js} +3 -3
  45. package/dist/{consensus-vote-MVZ27Y43.js → consensus-vote-ZBSY2SCU.js} +15 -15
  46. package/dist/{context-retriever-5OVRAWNZ.js → context-retriever-BWLNV73G.js} +9 -9
  47. package/dist/{doctor-deep-HJ3NQ365.js → doctor-deep-JW3Y5ZD2.js} +4 -4
  48. package/dist/{expert-bridge-MINXBC73.js → expert-bridge-4YXDWOMR.js} +5 -5
  49. package/dist/factory-3HBHEN54.js +14 -0
  50. package/dist/factory-7XUQGSHC.js +21 -0
  51. package/dist/{improvement-review-ZL3364R2.js → improvement-review-GUPEYLGP.js} +7 -5
  52. package/dist/index.d.ts +230 -205
  53. package/dist/index.js +30 -30
  54. package/dist/{init-opencode-L3NT524E.js → init-opencode-3ETCD3BE.js} +7 -7
  55. package/dist/issue-triage-7QHWTJRD.js +16 -0
  56. package/dist/{learning-persistence-QFCQ5POD.js → learning-persistence-2KO4CXNL.js} +2 -2
  57. package/dist/{pr-reviewer-helpers-PLKDVWYF.js → pr-reviewer-helpers-56FWDR3G.js} +5 -5
  58. package/dist/{registry-command-HPKNLYUL.js → registry-command-PYAMTDT2.js} +3 -3
  59. package/dist/{repo-security-plan-HSYGGVEJ.js → repo-security-plan-WJM2JXPT.js} +4 -4
  60. package/dist/research-helpers-synthesize-K4Z4BYGI.js +14 -0
  61. package/dist/{routing-memory-OGUOL7UF.js → routing-memory-K54FC6WD.js} +3 -3
  62. package/dist/{session-memory-HQWAXH3C.js → session-memory-G5DWGR6S.js} +4 -4
  63. package/dist/{setup-command-CIXJXFPC.js → setup-command-7IN7ORLV.js} +12 -12
  64. package/dist/setup-config-PTRDCT22.js +10 -0
  65. package/dist/{setup-custom-api-W7EDVKWR.js → setup-custom-api-2IDPBBER.js} +4 -4
  66. package/dist/{tool-memory-Z2B7CAH7.js → tool-memory-GGQVY2GX.js} +6 -6
  67. package/dist/unified-registry-3QASCESS.js +24 -0
  68. package/dist/{weather-report-GX7OIUL2.js → weather-report-RYUENMV5.js} +3 -3
  69. package/package.json +1 -1
  70. package/dist/chunk-4CVITS5D.js.map +0 -1
  71. package/dist/chunk-QJIHSQZX.js.map +0 -1
  72. package/dist/chunk-RJEP2AZW.js.map +0 -1
  73. package/dist/chunk-ZVBGZBW5.js.map +0 -1
  74. package/dist/factory-KC7BYHAP.js +0 -21
  75. package/dist/factory-ZG2FZYVA.js +0 -14
  76. package/dist/issue-triage-CZPFNGB7.js +0 -16
  77. package/dist/research-helpers-synthesize-IQHDU27S.js +0 -14
  78. package/dist/setup-config-HYX3BRSE.js +0 -10
  79. package/dist/unified-registry-UFNSWKZA.js +0 -24
  80. /package/dist/{child-mcp-config-R67B2KM6.js.map → child-mcp-config-RIEZRHWO.js.map} +0 -0
  81. /package/dist/{chunk-RLYXX3FQ.js.map → chunk-2QTDOKWV.js.map} +0 -0
  82. /package/dist/{chunk-K5WBFAR4.js.map → chunk-3IT473PY.js.map} +0 -0
  83. /package/dist/{chunk-J435FU54.js.map → chunk-4L4VXVKC.js.map} +0 -0
  84. /package/dist/{chunk-WHZD2W6Q.js.map → chunk-4NANSSKX.js.map} +0 -0
  85. /package/dist/{chunk-NZGNOXXW.js.map → chunk-52N3NGEY.js.map} +0 -0
  86. /package/dist/{chunk-EFDXX5MC.js.map → chunk-5MWNLEU2.js.map} +0 -0
  87. /package/dist/{chunk-ECDJM6UB.js.map → chunk-BGGX3BXC.js.map} +0 -0
  88. /package/dist/{chunk-2CLFX73Y.js.map → chunk-C46YFMFO.js.map} +0 -0
  89. /package/dist/{chunk-CI5KGCX5.js.map → chunk-C4GDV57D.js.map} +0 -0
  90. /package/dist/{chunk-S4U3Z6ZS.js.map → chunk-C5FWXNAR.js.map} +0 -0
  91. /package/dist/{chunk-TGGR6ST5.js.map → chunk-DXVQ6VFB.js.map} +0 -0
  92. /package/dist/{chunk-PM63X3QG.js.map → chunk-FGQL4LZP.js.map} +0 -0
  93. /package/dist/{chunk-DETYVPZO.js.map → chunk-FNYTCR6R.js.map} +0 -0
  94. /package/dist/{chunk-QLRH6KOT.js.map → chunk-GM5F2FO5.js.map} +0 -0
  95. /package/dist/{chunk-7BONPRR2.js.map → chunk-HDBV64A3.js.map} +0 -0
  96. /package/dist/{chunk-ZTRBMKXK.js.map → chunk-HGYJLSLL.js.map} +0 -0
  97. /package/dist/{chunk-XIFOAZ5B.js.map → chunk-ILH5TZAX.js.map} +0 -0
  98. /package/dist/{chunk-GET2MTLW.js.map → chunk-JA3SDBVY.js.map} +0 -0
  99. /package/dist/{chunk-HGUO36KW.js.map → chunk-JWWCNN76.js.map} +0 -0
  100. /package/dist/{chunk-VZCQRLXT.js.map → chunk-K5O7SSOH.js.map} +0 -0
  101. /package/dist/{chunk-4CLBJ2NA.js.map → chunk-MREIJMH7.js.map} +0 -0
  102. /package/dist/{chunk-FKTLAPXJ.js.map → chunk-OQZQITVU.js.map} +0 -0
  103. /package/dist/{chunk-QMCHVYZB.js.map → chunk-QX2Y5QWO.js.map} +0 -0
  104. /package/dist/{chunk-4DLHM6LI.js.map → chunk-SMRXY5ZN.js.map} +0 -0
  105. /package/dist/{chunk-27DRQWON.js.map → chunk-T77RGBUF.js.map} +0 -0
  106. /package/dist/{chunk-ZQEQVCIU.js.map → chunk-V6XZFDFR.js.map} +0 -0
  107. /package/dist/{chunk-E4IYX7LD.js.map → chunk-WRP5COST.js.map} +0 -0
  108. /package/dist/{chunk-RAWF4JOT.js.map → chunk-XM3OQXN5.js.map} +0 -0
  109. /package/dist/{chunk-GYDO2WOR.js.map → chunk-ZVIBVJBI.js.map} +0 -0
  110. /package/dist/{cli-circuit-breaker-J6UFONNE.js.map → cli-circuit-breaker-QONQNI3B.js.map} +0 -0
  111. /package/dist/{composite-router-HQUSCJO4.js.map → composite-router-DU22RBNQ.js.map} +0 -0
  112. /package/dist/{consensus-vote-MVZ27Y43.js.map → consensus-vote-ZBSY2SCU.js.map} +0 -0
  113. /package/dist/{context-retriever-5OVRAWNZ.js.map → context-retriever-BWLNV73G.js.map} +0 -0
  114. /package/dist/{doctor-deep-HJ3NQ365.js.map → doctor-deep-JW3Y5ZD2.js.map} +0 -0
  115. /package/dist/{expert-bridge-MINXBC73.js.map → expert-bridge-4YXDWOMR.js.map} +0 -0
  116. /package/dist/{factory-KC7BYHAP.js.map → factory-3HBHEN54.js.map} +0 -0
  117. /package/dist/{factory-ZG2FZYVA.js.map → factory-7XUQGSHC.js.map} +0 -0
  118. /package/dist/{improvement-review-ZL3364R2.js.map → improvement-review-GUPEYLGP.js.map} +0 -0
  119. /package/dist/{init-opencode-L3NT524E.js.map → init-opencode-3ETCD3BE.js.map} +0 -0
  120. /package/dist/{issue-triage-CZPFNGB7.js.map → issue-triage-7QHWTJRD.js.map} +0 -0
  121. /package/dist/{learning-persistence-QFCQ5POD.js.map → learning-persistence-2KO4CXNL.js.map} +0 -0
  122. /package/dist/{pr-reviewer-helpers-PLKDVWYF.js.map → pr-reviewer-helpers-56FWDR3G.js.map} +0 -0
  123. /package/dist/{registry-command-HPKNLYUL.js.map → registry-command-PYAMTDT2.js.map} +0 -0
  124. /package/dist/{repo-security-plan-HSYGGVEJ.js.map → repo-security-plan-WJM2JXPT.js.map} +0 -0
  125. /package/dist/{research-helpers-synthesize-IQHDU27S.js.map → research-helpers-synthesize-K4Z4BYGI.js.map} +0 -0
  126. /package/dist/{routing-memory-OGUOL7UF.js.map → routing-memory-K54FC6WD.js.map} +0 -0
  127. /package/dist/{session-memory-HQWAXH3C.js.map → session-memory-G5DWGR6S.js.map} +0 -0
  128. /package/dist/{setup-command-CIXJXFPC.js.map → setup-command-7IN7ORLV.js.map} +0 -0
  129. /package/dist/{setup-config-HYX3BRSE.js.map → setup-config-PTRDCT22.js.map} +0 -0
  130. /package/dist/{setup-custom-api-W7EDVKWR.js.map → setup-custom-api-2IDPBBER.js.map} +0 -0
  131. /package/dist/{tool-memory-Z2B7CAH7.js.map → tool-memory-GGQVY2GX.js.map} +0 -0
  132. /package/dist/{unified-registry-UFNSWKZA.js.map → unified-registry-3QASCESS.js.map} +0 -0
  133. /package/dist/{weather-report-GX7OIUL2.js.map → weather-report-RYUENMV5.js.map} +0 -0
@@ -7,21 +7,23 @@ import {
7
7
  toolStructuredError,
8
8
  toolSuccessStructured,
9
9
  wrapToolWithTimeout
10
- } from "./chunk-4CLBJ2NA.js";
10
+ } from "./chunk-MREIJMH7.js";
11
11
  import {
12
12
  JsonlStore,
13
13
  SECURITY_KEYWORDS,
14
14
  createLogger,
15
+ declaredOrthogonalityGroup,
15
16
  formatZodError,
16
17
  getErrorMessage,
17
18
  getOutcomeStore,
18
19
  getPipelineEventBus,
19
- getTimeProvider
20
- } from "./chunk-QJIHSQZX.js";
20
+ getTimeProvider,
21
+ isDeclaredNeverDeprecate
22
+ } from "./chunk-CBJN5MYW.js";
21
23
  import {
22
24
  getNexusDataDir,
23
25
  nexusDataPath
24
- } from "./chunk-RUSP5PJR.js";
26
+ } from "./chunk-GZ4NF4ZW.js";
25
27
 
26
28
  // src/mcp/tools/improvement-review.ts
27
29
  import { execFile as execFile2 } from "child_process";
@@ -108,6 +110,9 @@ function withPrerequisite(toolName, handler) {
108
110
  return applyPrerequisite(toolName, prereq, handler);
109
111
  }
110
112
 
113
+ // src/mcp/tools/improvement-review.ts
114
+ import { createHash } from "crypto";
115
+
111
116
  // src/governance/fitness-score.ts
112
117
  import { existsSync, readFileSync, readdirSync, statSync } from "fs";
113
118
  import { join } from "path";
@@ -172,6 +177,16 @@ function countPatternInDir(dir, filePattern, contentPattern, excludePatterns) {
172
177
  }
173
178
  return count;
174
179
  }
180
+ var FITNESS_DIMENSION_MAX = {
181
+ canonicalPaths: 20,
182
+ explicitBehavior: 15,
183
+ determinism: 15,
184
+ observability: 15,
185
+ configSimplicity: 10,
186
+ layerSeparation: 10,
187
+ operatorErgonomics: 10,
188
+ governanceIntegration: 5
189
+ };
175
190
  function clamp(score, max) {
176
191
  return Math.max(0, Math.min(max, score));
177
192
  }
@@ -184,19 +199,18 @@ var FitnessScoreCalculator = class {
184
199
  }
185
200
  /** Register default fitness checks. */
186
201
  registerDefaultChecks() {
187
- const reg = (dimension, maxPoints, name, check) => {
188
- this.checks.push({ dimension, maxPoints, name, check });
202
+ const reg = (dimension, name, check) => {
203
+ this.checks.push({ dimension, maxPoints: FITNESS_DIMENSION_MAX[dimension], name, check });
189
204
  };
190
- reg("canonicalPaths", 20, "Canonical Paths", () => this.checkCanonicalPaths());
191
- reg("explicitBehavior", 15, "Explicit Behavior", () => this.checkExplicitBehavior());
192
- reg("determinism", 15, "Determinism", () => this.checkDeterminism());
193
- reg("observability", 15, "Observability", () => this.checkObservability());
194
- reg("configSimplicity", 10, "Config Simplicity", () => this.checkConfigSimplicity());
195
- reg("layerSeparation", 10, "Layer Separation", () => this.checkLayerSeparation());
196
- reg("operatorErgonomics", 10, "Operator Ergonomics", () => this.checkOperatorErgonomics());
205
+ reg("canonicalPaths", "Canonical Paths", () => this.checkCanonicalPaths());
206
+ reg("explicitBehavior", "Explicit Behavior", () => this.checkExplicitBehavior());
207
+ reg("determinism", "Determinism", () => this.checkDeterminism());
208
+ reg("observability", "Observability", () => this.checkObservability());
209
+ reg("configSimplicity", "Config Simplicity", () => this.checkConfigSimplicity());
210
+ reg("layerSeparation", "Layer Separation", () => this.checkLayerSeparation());
211
+ reg("operatorErgonomics", "Operator Ergonomics", () => this.checkOperatorErgonomics());
197
212
  reg(
198
213
  "governanceIntegration",
199
- 5,
200
214
  "Governance Integration",
201
215
  () => this.checkGovernanceIntegration()
202
216
  );
@@ -742,6 +756,7 @@ var DEFAULT_NEVER_DEPRECATE_PATTERNS = [
742
756
  "quarantine"
743
757
  ];
744
758
  function isNeverDeprecate(tool, config) {
759
+ if (isDeclaredNeverDeprecate(tool)) return true;
745
760
  if (config?.exemptTools?.includes(tool) === true) return true;
746
761
  const lower = tool.toLowerCase();
747
762
  const patterns = [...DEFAULT_NEVER_DEPRECATE_PATTERNS, ...config?.extraPatterns ?? []];
@@ -763,6 +778,11 @@ function verbGroup(verb) {
763
778
  return ORTHOGONAL_VERB_GROUPS.findIndex((g) => g.includes(verb));
764
779
  }
765
780
  function consolidationConfidence(candidate, busiest) {
781
+ const declaredA = declaredOrthogonalityGroup(candidate.tool);
782
+ const declaredB = declaredOrthogonalityGroup(busiest.tool);
783
+ if (declaredA !== void 0 && declaredB !== void 0) {
784
+ return declaredA !== declaredB ? "none" : "low";
785
+ }
766
786
  const a = verbGroup(actionVerb(candidate.tool));
767
787
  const b = verbGroup(actionVerb(busiest.tool));
768
788
  if (a !== -1 && b !== -1 && a !== b) return "none";
@@ -1109,6 +1129,95 @@ function loadToolFitnessSignals(windowLabel, ledger = getToolFitnessLedger()) {
1109
1129
  }
1110
1130
  }
1111
1131
 
1132
+ // src/mcp/tools/improvement-review-perf-regression.ts
1133
+ var DEFAULT_REGRESSION_TOLERANCE_FRACTION = 0.2;
1134
+ function baselineKey(component, operation) {
1135
+ return `${component}::${operation}`;
1136
+ }
1137
+ function round2(n) {
1138
+ return Math.round(n * 100) / 100;
1139
+ }
1140
+ function pctWorse(measured, baseline) {
1141
+ if (baseline === 0) return 0;
1142
+ return round2(Math.abs(measured - baseline) / baseline * 100);
1143
+ }
1144
+ function latencyRegressionSignal(component, operation, measuredP95Ms, baselineP95Ms, tolerance) {
1145
+ const threshold = baselineP95Ms * (1 + tolerance);
1146
+ if (measuredP95Ms <= threshold) return void 0;
1147
+ const deltaPct = pctWorse(measuredP95Ms, baselineP95Ms);
1148
+ return {
1149
+ category: "perf-regression",
1150
+ signalKey: `perf-regression:latency:${component}:${operation}`,
1151
+ severity: "warning",
1152
+ title: `perf-regression: ${component}/${operation} p95 latency ${String(round2(measuredP95Ms))}ms vs baseline ${String(round2(baselineP95Ms))}ms (+${String(deltaPct)}%)`,
1153
+ body: [
1154
+ `Measured p95 latency regressed beyond the configured tolerance against a STATIC baseline.`,
1155
+ "",
1156
+ `- Component: \`${component}\``,
1157
+ `- Operation: \`${operation}\``,
1158
+ `- Measured p95: ${String(round2(measuredP95Ms))} ms`,
1159
+ `- Baseline p95: ${String(round2(baselineP95Ms))} ms (static/configured \u2014 not a rolling window)`,
1160
+ `- Tolerance: ${String(round2(tolerance * 100))}% (regression threshold ${String(round2(threshold))} ms)`,
1161
+ `- Delta: +${String(deltaPct)}% worse than baseline`,
1162
+ "",
1163
+ "Surfaced as a candidate finding for human review. No fitness/governance score is mutated and no remediation is auto-applied."
1164
+ ].join("\n"),
1165
+ evidence: { observedValue: round2(measuredP95Ms), threshold: round2(threshold) }
1166
+ };
1167
+ }
1168
+ function throughputRegressionSignal(component, operation, measuredThroughput, baselineThroughput, tolerance) {
1169
+ const threshold = baselineThroughput * (1 - tolerance);
1170
+ if (measuredThroughput >= threshold) return void 0;
1171
+ const deltaPct = pctWorse(measuredThroughput, baselineThroughput);
1172
+ return {
1173
+ category: "perf-regression",
1174
+ signalKey: `perf-regression:throughput:${component}:${operation}`,
1175
+ severity: "warning",
1176
+ title: `perf-regression: ${component}/${operation} throughput ${String(round2(measuredThroughput))} ops/s vs baseline ${String(round2(baselineThroughput))} ops/s (-${String(deltaPct)}%)`,
1177
+ body: [
1178
+ `Measured throughput regressed beyond the configured tolerance against a STATIC baseline.`,
1179
+ "",
1180
+ `- Component: \`${component}\``,
1181
+ `- Operation: \`${operation}\``,
1182
+ `- Measured throughput: ${String(round2(measuredThroughput))} ops/s`,
1183
+ `- Baseline throughput: ${String(round2(baselineThroughput))} ops/s (static/configured \u2014 not a rolling window)`,
1184
+ `- Tolerance: ${String(round2(tolerance * 100))}% (regression threshold ${String(round2(threshold))} ops/s)`,
1185
+ `- Delta: -${String(deltaPct)}% below baseline`,
1186
+ "",
1187
+ "Surfaced as a candidate finding for human review. No fitness/governance score is mutated and no remediation is auto-applied."
1188
+ ].join("\n"),
1189
+ evidence: { observedValue: round2(measuredThroughput), threshold: round2(threshold) }
1190
+ };
1191
+ }
1192
+ function detectPerfRegressionSignals(result, baselines, tolerance = DEFAULT_REGRESSION_TOLERANCE_FRACTION) {
1193
+ const signals = [];
1194
+ for (const op of result.operations) {
1195
+ const baseline = baselines.get(baselineKey(result.component, op.operation));
1196
+ if (baseline === void 0) continue;
1197
+ if (baseline.baselineP95Ms !== void 0) {
1198
+ const sig = latencyRegressionSignal(
1199
+ result.component,
1200
+ op.operation,
1201
+ op.latency.p95,
1202
+ baseline.baselineP95Ms,
1203
+ tolerance
1204
+ );
1205
+ if (sig !== void 0) signals.push(sig);
1206
+ }
1207
+ if (baseline.baselineThroughput !== void 0) {
1208
+ const sig = throughputRegressionSignal(
1209
+ result.component,
1210
+ op.operation,
1211
+ op.throughput.opsPerSecond,
1212
+ baseline.baselineThroughput,
1213
+ tolerance
1214
+ );
1215
+ if (sig !== void 0) signals.push(sig);
1216
+ }
1217
+ }
1218
+ return signals;
1219
+ }
1220
+
1112
1221
  // src/mcp/tools/improvement-remediation.ts
1113
1222
  var ROLE_BY_CATEGORY = {
1114
1223
  security: "security",
@@ -1119,7 +1228,11 @@ var ROLE_BY_CATEGORY = {
1119
1228
  // #3852: tool-fitness candidates are deprecation/consolidation proposals —
1120
1229
  // a researcher owns the investigation seed (suggest-tier; the dev-pipeline
1121
1230
  // re-plans anyway). NEVER an autonomous removal.
1122
- "tool-fitness": "researcher"
1231
+ "tool-fitness": "researcher",
1232
+ // #3692/#3246: a perf regression vs a static baseline is a performance
1233
+ // investigation seed — a coder owns the diagnosis. Surfaced-only; the
1234
+ // dev-pipeline re-plans, nothing is auto-applied.
1235
+ "perf-regression": "coder"
1123
1236
  };
1124
1237
  function remediationTaskId(signal) {
1125
1238
  return `improvement-${signal.signalKey}`;
@@ -1621,24 +1734,104 @@ function buildFloorSignal(audit, fitnessFloor) {
1621
1734
  evidence: { observedValue: audit.score, threshold: fitnessFloor }
1622
1735
  };
1623
1736
  }
1737
+ var FITNESS_DIMENSION_TARGET_FRACTION = 0.6;
1738
+ var MAX_DIMENSION_SIGNALS_PER_RUN = 3;
1739
+ var MAX_FINDING_TEXT_LEN = 280;
1740
+ var MAX_FINDINGS_IN_DIMENSION_BODY = 10;
1741
+ var STRUCTURALLY_UNREACHABLE_DIMENSIONS = /* @__PURE__ */ new Set(
1742
+ []
1743
+ );
1744
+ var KNOWN_DIMENSIONS = new Set(
1745
+ Object.keys(FITNESS_DIMENSION_MAX)
1746
+ );
1747
+ function capText(text) {
1748
+ return text.length > MAX_FINDING_TEXT_LEN ? `${text.slice(0, MAX_FINDING_TEXT_LEN)}\u2026` : text;
1749
+ }
1750
+ function findingBodyLines(finding) {
1751
+ return [
1752
+ `- Description: ${capText(finding.description)}`,
1753
+ `- Points deducted: ${String(finding.pointsDeducted)}`,
1754
+ finding.location !== void 0 ? `- Location: ${capText(finding.location)}` : "",
1755
+ finding.suggestion !== void 0 ? `- Suggestion: ${capText(finding.suggestion)}` : ""
1756
+ ].filter((line) => line.length > 0);
1757
+ }
1758
+ function findingIdentifier(finding) {
1759
+ return `${finding.dimension}|${finding.severity}|${finding.description}|${finding.location ?? ""}`;
1760
+ }
1624
1761
  function buildCriticalFindingSignal(finding) {
1625
1762
  return {
1626
1763
  category: "tech-debt",
1627
1764
  signalKey: `tech-debt:fitness-critical:${finding.dimension}`,
1628
1765
  severity: "critical",
1629
1766
  title: `tech-debt: critical fitness finding in ${finding.dimension}`,
1767
+ body: [`Fitness audit returned a CRITICAL finding.`, "", `- Dimension: \`${finding.dimension}\``, ...findingBodyLines(finding)].join(
1768
+ "\n"
1769
+ ),
1770
+ evidence: { observedValue: -finding.pointsDeducted }
1771
+ };
1772
+ }
1773
+ function detectDimensionBreaches(audit) {
1774
+ const findingsByDimension = /* @__PURE__ */ new Map();
1775
+ for (const f of audit.findings) {
1776
+ if (!KNOWN_DIMENSIONS.has(f.dimension)) continue;
1777
+ const list = findingsByDimension.get(f.dimension) ?? [];
1778
+ list.push(f);
1779
+ findingsByDimension.set(f.dimension, list);
1780
+ }
1781
+ const breaches = [];
1782
+ for (const dimension of KNOWN_DIMENSIONS) {
1783
+ if (STRUCTURALLY_UNREACHABLE_DIMENSIONS.has(dimension)) continue;
1784
+ const max = FITNESS_DIMENSION_MAX[dimension];
1785
+ const score = audit.dimensions[dimension];
1786
+ if (typeof score !== "number") continue;
1787
+ const target = FITNESS_DIMENSION_TARGET_FRACTION * max;
1788
+ if (score >= target) continue;
1789
+ breaches.push({
1790
+ dimension,
1791
+ score,
1792
+ max,
1793
+ target,
1794
+ pointsBelowTarget: target - score,
1795
+ findings: findingsByDimension.get(dimension) ?? []
1796
+ });
1797
+ }
1798
+ breaches.sort(
1799
+ (a, b) => b.pointsBelowTarget - a.pointsBelowTarget || a.dimension.localeCompare(b.dimension)
1800
+ );
1801
+ return breaches;
1802
+ }
1803
+ function buildDimensionSignal(breach) {
1804
+ const sortedIds = breach.findings.map(findingIdentifier).sort();
1805
+ const dedup = createHash("sha256").update([breach.dimension, ...sortedIds].join("\0")).digest("hex").slice(0, 12);
1806
+ const findingLines = breach.findings.length === 0 ? ["_No itemized findings recorded for this dimension \u2014 score is below target on aggregate._"] : breach.findings.slice(0, MAX_FINDINGS_IN_DIMENSION_BODY).flatMap((f, i) => [`${String(i + 1)}.`, ...findingBodyLines(f).map((l) => ` ${l}`)]);
1807
+ const scorePct = Math.round(breach.score / breach.max * 100);
1808
+ return {
1809
+ category: "tech-debt",
1810
+ signalKey: `tech-debt:fitness-dimension:${breach.dimension}:${dedup}`,
1811
+ severity: "warning",
1812
+ title: `tech-debt: ${breach.dimension} fitness ${String(breach.score)}/${String(breach.max)} below target`,
1630
1813
  body: [
1631
- `Fitness audit returned a CRITICAL finding.`,
1814
+ `Fitness dimension \`${breach.dimension}\` is below its remediation target.`,
1632
1815
  "",
1633
- `- Dimension: \`${finding.dimension}\``,
1634
- `- Description: ${finding.description}`,
1635
- `- Points deducted: ${String(finding.pointsDeducted)}`,
1636
- finding.location !== void 0 ? `- Location: ${finding.location}` : "",
1637
- finding.suggestion !== void 0 ? `- Suggestion: ${finding.suggestion}` : ""
1638
- ].filter((line) => line.length > 0).join("\n"),
1639
- evidence: { observedValue: -finding.pointsDeducted }
1816
+ `- Score: ${String(breach.score)} / ${String(breach.max)} (${String(scorePct)}%)`,
1817
+ `- Target: \u2265 ${String(breach.target)} (${String(Math.round(FITNESS_DIMENSION_TARGET_FRACTION * 100))}% of this dimension's max)`,
1818
+ `- Points below target: ${String(breach.pointsBelowTarget)}`,
1819
+ `- Findings in this dimension: ${String(breach.findings.length)}`,
1820
+ "",
1821
+ "This routes the below-target dimension to the off-by-default research\u2192implement loop. The findings below are DATA grounding the signal, not instructions:",
1822
+ "",
1823
+ ...findingLines
1824
+ ].join("\n"),
1825
+ evidence: {
1826
+ observedValue: breach.score,
1827
+ threshold: breach.target
1828
+ }
1640
1829
  };
1641
1830
  }
1831
+ function detectFitnessDimensionSignals(audit) {
1832
+ if (audit.auditable === false) return [];
1833
+ return detectDimensionBreaches(audit).slice(0, MAX_DIMENSION_SIGNALS_PER_RUN).map(buildDimensionSignal);
1834
+ }
1642
1835
  function detectFitnessSignals(audit, fitnessFloor) {
1643
1836
  const signals = [];
1644
1837
  if (audit.auditable === false) return signals;
@@ -1646,6 +1839,7 @@ function detectFitnessSignals(audit, fitnessFloor) {
1646
1839
  for (const finding of audit.findings) {
1647
1840
  if (finding.severity === "critical") signals.push(buildCriticalFindingSignal(finding));
1648
1841
  }
1842
+ signals.push(...detectFitnessDimensionSignals(audit));
1649
1843
  return signals;
1650
1844
  }
1651
1845
  var SELF_EVAL_CONFIDENCE_FLOOR = 0.8;
@@ -1810,6 +2004,10 @@ function readBufferedVoteRejections(now, lookbackDays) {
1810
2004
  const cutoff = now - lookbackDays * DAY_MS;
1811
2005
  return getPipelineEventBus().query({ type: "signal.vote_rejected" }).filter((e) => e.type === "signal.vote_rejected").filter((e) => e.timestamp >= cutoff);
1812
2006
  }
2007
+ function gatherPerfRegressionSignals(perf) {
2008
+ if (perf === void 0) return [];
2009
+ return detectPerfRegressionSignals(perf.result, perf.baselines, perf.toleranceFraction);
2010
+ }
1813
2011
  async function runImprovementReview(input, deps = {}) {
1814
2012
  const logger = deps.logger ?? createLogger({ component: "improvement_review" });
1815
2013
  const { lookbackDays, fileIssues, minSampleSize, fitnessFloor, selfEvalReportPath } = input;
@@ -1821,13 +2019,15 @@ async function runImprovementReview(input, deps = {}) {
1821
2019
  const selfEvalSignals = selfEvalReportPath !== void 0 ? await loadSelfEvalSignals(selfEvalReportPath, windowLabel, logger) : [];
1822
2020
  const rejectionEvents = readBufferedVoteRejections(now, lookbackDays);
1823
2021
  const toolFitnessSignals = loadToolFitnessSignals(windowLabel);
2022
+ const perfRegressionSignals = gatherPerfRegressionSignals(deps.perfRegression);
1824
2023
  const signals = [
1825
2024
  ...detectCliPerformanceFloor(windowed, minSampleSize, windowLabel),
1826
2025
  ...detectFailureCategoryConcentration(windowed, windowLabel),
1827
2026
  ...detectFitnessSignals(audit, fitnessFloor),
1828
2027
  ...detectConsensusRejectionSignals(rejectionEvents, windowLabel),
1829
2028
  ...selfEvalSignals,
1830
- ...toolFitnessSignals
2029
+ ...toolFitnessSignals,
2030
+ ...perfRegressionSignals
1831
2031
  ];
1832
2032
  signals.sort((a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity]);
1833
2033
  emitFitnessDeclinedSignal(audit, fitnessFloor, getPipelineEventBus(), logger);
@@ -1924,6 +2124,7 @@ export {
1924
2124
  detectCliPerformanceFloor,
1925
2125
  detectConsensusRejectionSignals,
1926
2126
  detectFailureCategoryConcentration,
2127
+ detectFitnessDimensionSignals,
1927
2128
  detectFitnessSignals,
1928
2129
  detectSelfEvalSignals,
1929
2130
  loadSelfEvalSignals,
@@ -1931,4 +2132,4 @@ export {
1931
2132
  runImprovementReview,
1932
2133
  registerImprovementReviewTool
1933
2134
  };
1934
- //# sourceMappingURL=chunk-ZVBGZBW5.js.map
2135
+ //# sourceMappingURL=chunk-KAIRRC5R.js.map