@lmzhen/dsh-evolution-replay 0.3.68 → 0.3.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -64,7 +64,7 @@ function scorePlan(plan, weights = DEFAULT_WEIGHTS) {
64
64
  function comparePlans(plans, weights = DEFAULT_WEIGHTS) {
65
65
  if (plans.length === 0) return {
66
66
  winner: null,
67
- margin: 0,
67
+ margin: null,
68
68
  plans,
69
69
  report: "No plans to compare."
70
70
  };
@@ -75,17 +75,18 @@ function comparePlans(plans, weights = DEFAULT_WEIGHTS) {
75
75
  const winner = scored[0];
76
76
  if (!winner) return {
77
77
  winner: null,
78
- margin: 0,
78
+ margin: null,
79
79
  plans,
80
80
  report: "No plans to compare."
81
81
  };
82
82
  const runnerUp = scored[1];
83
- const margin = runnerUp ? winner.score - runnerUp.score : winner.score;
83
+ const margin = runnerUp ? winner.score - runnerUp.score : null;
84
+ const singleNote = runnerUp ? "" : "\n(single plan recorded — margin is not a comparison)";
84
85
  return {
85
86
  winner: winner.plan.policyId,
86
87
  margin,
87
88
  plans,
88
- report: scored.map(({ plan, score }) => `${plan.policyId}: ${score.toFixed(1)} (${plan.acceptedOps} accepted, ${plan.rejectedOps} rejected${(plan.executionFailures ?? 0) > 0 ? `, ${plan.executionFailures} failed${plan.executionError !== void 0 ? `: ${plan.executionError}` : ""}` : ""})`).join("\n")
89
+ report: scored.map(({ plan, score }) => `${plan.policyId}: ${score.toFixed(1)} (${plan.acceptedOps} accepted, ${plan.rejectedOps} rejected${(plan.executionFailures ?? 0) > 0 ? `, ${plan.executionFailures} failed${plan.executionError !== void 0 ? `: ${plan.executionError}` : ""}` : ""})`).join("\n") + singleNote
89
90
  };
90
91
  }
91
92
  var EvolutionReplayDriver = class EvolutionReplayDriver {
@@ -129,11 +130,21 @@ var EvolutionReplayDriver = class EvolutionReplayDriver {
129
130
  this.preBackfillIds.delete(oldest);
130
131
  }
131
132
  }
133
+ this.plans.push(this.toPlan(plan));
134
+ if (this.plans.length > this.maxPlans) this.plans.shift();
135
+ }
136
+ /**
137
+ * v29 RPL-02: the activity/event record → scored-plan mapping, extracted
138
+ * from `record` so `backfill` can place sidecar plans at the CHRONOLOGICAL
139
+ * head of the window instead of appending them after this boot's live plans
140
+ * (the old order made the FIFO evict the freshest live plan first).
141
+ */
142
+ toPlan(plan) {
132
143
  const count = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
133
144
  const countOr = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
134
145
  const memoryApplied = count(plan.memoryApplied);
135
146
  const skillApplied = count(plan.skillApplied);
136
- this.plans.push({
147
+ return {
137
148
  policyId: typeof plan.policyFingerprint === "string" && plan.policyFingerprint.length > 0 ? plan.policyFingerprint : plan.planId,
138
149
  acceptedOps: memoryApplied + skillApplied,
139
150
  rejectedOps: count(plan.rejectedOps),
@@ -143,8 +154,7 @@ var EvolutionReplayDriver = class EvolutionReplayDriver {
143
154
  estimatedInputChars: count(plan.estimatedInputChars),
144
155
  executionFailures: count(plan.executionFailures),
145
156
  ...typeof plan.executionError === "string" ? { executionError: plan.executionError } : {}
146
- });
147
- if (this.plans.length > this.maxPlans) this.plans.shift();
157
+ };
148
158
  }
149
159
  /**
150
160
  * V25-01 (v25): backfill the leaderboard from the activity sidecar, ONCE
@@ -160,7 +170,9 @@ var EvolutionReplayDriver = class EvolutionReplayDriver {
160
170
  this.backfilled = true;
161
171
  const fresh = items.filter((item) => !this.preBackfillIds.has(item.planId));
162
172
  this.preBackfillIds.clear();
163
- for (const item of fresh) this.record(item);
173
+ const freshPlans = fresh.map((item) => this.toPlan(item));
174
+ this.plans.unshift(...freshPlans);
175
+ if (this.plans.length > this.maxPlans) this.plans.splice(0, this.plans.length - this.maxPlans);
164
176
  }
165
177
  /**
166
178
  * F-11: test-support API — no production consumer reads the raw
@@ -35,7 +35,10 @@ export interface ReplayPlan {
35
35
  }
36
36
  export interface ReplayResult {
37
37
  winner: string | null;
38
- margin: number;
38
+ /** v28 G4.4 (RPL-01): `null` when fewer than two plans were recorded — a
39
+ * single plan has no runner-up, and reporting its FULL score as a "margin"
40
+ * read as "won by N points" over nothing. Consumers must null-check. */
41
+ margin: number | null;
39
42
  plans: ReplayPlan[];
40
43
  report: string;
41
44
  }
@@ -88,6 +91,13 @@ export declare class EvolutionReplayDriver {
88
91
  private readonly weights;
89
92
  constructor(config?: Config, warn?: (message: string) => void);
90
93
  record(plan: EvolutionPlanAppliedEvent): void;
94
+ /**
95
+ * v29 RPL-02: the activity/event record → scored-plan mapping, extracted
96
+ * from `record` so `backfill` can place sidecar plans at the CHRONOLOGICAL
97
+ * head of the window instead of appending them after this boot's live plans
98
+ * (the old order made the FIFO evict the freshest live plan first).
99
+ */
100
+ private toPlan;
91
101
  /**
92
102
  * V25-01 (v25): backfill the leaderboard from the activity sidecar, ONCE
93
103
  * per driver instance. The inject callback that loads the sidecar re-runs
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-replay",
3
3
  "description": "Replay/A-B evaluation primitives for evolution plans (community build)",
4
- "version": "0.3.68",
4
+ "version": "0.3.69",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,8 +31,8 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@deepseek-ai/schemastery": "^3.18.1",
34
- "@lmzhen/dsh-evolution-activity": "^0.3.68",
35
- "@lmzhen/dsh-evolution-core": "^0.3.68"
34
+ "@lmzhen/dsh-evolution-activity": "^0.3.69",
35
+ "@lmzhen/dsh-evolution-core": "^0.3.69"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@deepseek-ai/cordis": "^4.0.1",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "devDependencies": {
42
42
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
43
- "@lmzhen/dsh-evolution-activity": "^0.3.68",
44
- "@lmzhen/dsh-evolution-core": "^0.3.68"
43
+ "@lmzhen/dsh-evolution-activity": "^0.3.69",
44
+ "@lmzhen/dsh-evolution-core": "^0.3.69"
45
45
  }
46
46
  }