@hmharness/evolution 0.14.14 → 0.14.15

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.
@@ -64,11 +64,19 @@ export declare function exportDpoPairs(labels: HumanLabel[], insights: InsightLi
64
64
  crossBucketPrefix?: number;
65
65
  sources?: Map<string, 'human' | 'judge'>;
66
66
  }): DpoPair[];
67
- /** Deterministic ~80/20 train/eval split by pair identity. Pure. */
67
+ /** Deterministic ~80/20 split BY PROMPT (group split): bench templates
68
+ * mint many pairs per prompt, and a pair-level split leaked ~4.9k eval
69
+ * prompts into train (audit 2026-09-21) - every pair of one prompt must
70
+ * land on the same side or offline metrics are inflated. Pure. */
68
71
  export declare function splitDpoPairs(pairs: DpoPair[], salt?: string): {
69
72
  train: DpoPair[];
70
73
  eval: DpoPair[];
71
74
  };
75
+ /** Exact-duplicate removal (same prompt+chosen+rejected): the 5-star army
76
+ * against the same few degraded sessions minted 11k+ permutation copies
77
+ * (audit 2026-09-21) - training would just over-weight those templates.
78
+ * Keeps the first occurrence (deterministic). Pure. */
79
+ export declare function dedupeDpoPairs(pairs: DpoPair[]): DpoPair[];
72
80
  /** Leakage/quality audit before training consumes the pairs: empty sides,
73
81
  * exact duplicates, and eval pairs whose prompt ALSO appears in train
74
82
  * (prompt leakage inflates offline metrics). Pure. */
@@ -202,15 +202,34 @@ function fnv1a(str) {
202
202
  }
203
203
  return h >>> 0;
204
204
  }
205
- /** Deterministic ~80/20 train/eval split by pair identity. Pure. */
205
+ /** Deterministic ~80/20 split BY PROMPT (group split): bench templates
206
+ * mint many pairs per prompt, and a pair-level split leaked ~4.9k eval
207
+ * prompts into train (audit 2026-09-21) - every pair of one prompt must
208
+ * land on the same side or offline metrics are inflated. Pure. */
206
209
  export function splitDpoPairs(pairs, salt = 'dpo') {
207
210
  const train = [];
208
211
  const evalP = [];
209
212
  for (const p of pairs) {
210
- (fnv1a(salt + '|' + p.prompt + '|' + p.chosenSession + '|' + p.rejectedSession) % 5 === 0 ? evalP : train).push(p);
213
+ (fnv1a(salt + '|' + p.prompt) % 5 === 0 ? evalP : train).push(p);
211
214
  }
212
215
  return { train, eval: evalP };
213
216
  }
217
+ /** Exact-duplicate removal (same prompt+chosen+rejected): the 5-star army
218
+ * against the same few degraded sessions minted 11k+ permutation copies
219
+ * (audit 2026-09-21) - training would just over-weight those templates.
220
+ * Keeps the first occurrence (deterministic). Pure. */
221
+ export function dedupeDpoPairs(pairs) {
222
+ const seen = new Set();
223
+ const out = [];
224
+ for (const p of pairs) {
225
+ const key = p.prompt + '\u0000' + p.chosen + '\u0000' + p.rejected;
226
+ if (seen.has(key))
227
+ continue;
228
+ seen.add(key);
229
+ out.push(p);
230
+ }
231
+ return out;
232
+ }
214
233
  /** Leakage/quality audit before training consumes the pairs: empty sides,
215
234
  * exact duplicates, and eval pairs whose prompt ALSO appears in train
216
235
  * (prompt leakage inflates offline metrics). Pure. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hmharness/evolution",
3
- "version": "0.14.14",
3
+ "version": "0.14.15",
4
4
  "description": "hmharness evolution subsystem: persistent memory, insight capture, skill library, and the bench that gives evolution its fitness signal. First-class kernel citizen, not a plugin.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",