@lmzhen/dsh-evolution-replay 0.3.67 → 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 +40 -11
- package/lib/types/index.d.ts +22 -2
- package/package.json +5 -5
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:
|
|
67
|
+
margin: null,
|
|
68
68
|
plans,
|
|
69
69
|
report: "No plans to compare."
|
|
70
70
|
};
|
|
@@ -75,20 +75,21 @@ function comparePlans(plans, weights = DEFAULT_WEIGHTS) {
|
|
|
75
75
|
const winner = scored[0];
|
|
76
76
|
if (!winner) return {
|
|
77
77
|
winner: null,
|
|
78
|
-
margin:
|
|
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 :
|
|
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
|
-
var EvolutionReplayDriver = class {
|
|
92
|
+
var EvolutionReplayDriver = class EvolutionReplayDriver {
|
|
92
93
|
plans = [];
|
|
93
94
|
maxPlans;
|
|
94
95
|
/** V25-01 (v25): backfill-once latch — see {@link EvolutionReplayDriver.backfill}. */
|
|
@@ -96,8 +97,18 @@ var EvolutionReplayDriver = class {
|
|
|
96
97
|
/** V26-05 (v25): plan ids recorded live BEFORE the backfill settled. A
|
|
97
98
|
* plan-applied landing inside the one-shot `loadActivity` read window is
|
|
98
99
|
* recorded live AND persisted into the sidecar the backfill is reading —
|
|
99
|
-
* `backfill()` drops those ids so the event is not counted twice.
|
|
100
|
+
* `backfill()` drops those ids so the event is not counted twice.
|
|
101
|
+
*
|
|
102
|
+
* V27 INS-05: the set is BOUNDED. `backfill()` is the only place that cleared
|
|
103
|
+
* it, so a sidecar load that never succeeded (the inject callback's catch
|
|
104
|
+
* warns and does not retry until the io dependency is replaced) let every
|
|
105
|
+
* live plan id accumulate for the process lifetime. Past
|
|
106
|
+
* PRE_BACKFILL_ID_CAP the oldest ids are dropped: the dedupe window is then
|
|
107
|
+
* finite, and a dropped duplicate can at worst repeat an entry inside the
|
|
108
|
+
* `maxPlans` window instead of growing memory without bound. */
|
|
100
109
|
preBackfillIds = /* @__PURE__ */ new Set();
|
|
110
|
+
/** Upper bound on {@link EvolutionReplayDriver.preBackfillIds} (V27 INS-05). */
|
|
111
|
+
static PRE_BACKFILL_ID_CAP = 4096;
|
|
101
112
|
weights;
|
|
102
113
|
constructor(config = {}, warn = () => {}) {
|
|
103
114
|
const maxPlans = clampedNumber(config.maxPlans ?? 50, 50, { min: 1 });
|
|
@@ -111,12 +122,29 @@ var EvolutionReplayDriver = class {
|
|
|
111
122
|
}
|
|
112
123
|
}
|
|
113
124
|
record(plan) {
|
|
114
|
-
if (!this.backfilled)
|
|
125
|
+
if (!this.backfilled) {
|
|
126
|
+
this.preBackfillIds.add(plan.planId);
|
|
127
|
+
while (this.preBackfillIds.size > EvolutionReplayDriver.PRE_BACKFILL_ID_CAP) {
|
|
128
|
+
const oldest = this.preBackfillIds.keys().next().value;
|
|
129
|
+
if (oldest === void 0) break;
|
|
130
|
+
this.preBackfillIds.delete(oldest);
|
|
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) {
|
|
115
143
|
const count = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
|
|
116
144
|
const countOr = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
|
|
117
145
|
const memoryApplied = count(plan.memoryApplied);
|
|
118
146
|
const skillApplied = count(plan.skillApplied);
|
|
119
|
-
|
|
147
|
+
return {
|
|
120
148
|
policyId: typeof plan.policyFingerprint === "string" && plan.policyFingerprint.length > 0 ? plan.policyFingerprint : plan.planId,
|
|
121
149
|
acceptedOps: memoryApplied + skillApplied,
|
|
122
150
|
rejectedOps: count(plan.rejectedOps),
|
|
@@ -126,8 +154,7 @@ var EvolutionReplayDriver = class {
|
|
|
126
154
|
estimatedInputChars: count(plan.estimatedInputChars),
|
|
127
155
|
executionFailures: count(plan.executionFailures),
|
|
128
156
|
...typeof plan.executionError === "string" ? { executionError: plan.executionError } : {}
|
|
129
|
-
}
|
|
130
|
-
if (this.plans.length > this.maxPlans) this.plans.shift();
|
|
157
|
+
};
|
|
131
158
|
}
|
|
132
159
|
/**
|
|
133
160
|
* V25-01 (v25): backfill the leaderboard from the activity sidecar, ONCE
|
|
@@ -143,7 +170,9 @@ var EvolutionReplayDriver = class {
|
|
|
143
170
|
this.backfilled = true;
|
|
144
171
|
const fresh = items.filter((item) => !this.preBackfillIds.has(item.planId));
|
|
145
172
|
this.preBackfillIds.clear();
|
|
146
|
-
|
|
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);
|
|
147
176
|
}
|
|
148
177
|
/**
|
|
149
178
|
* F-11: test-support API — no production consumer reads the raw
|
package/lib/types/index.d.ts
CHANGED
|
@@ -35,7 +35,10 @@ export interface ReplayPlan {
|
|
|
35
35
|
}
|
|
36
36
|
export interface ReplayResult {
|
|
37
37
|
winner: string | null;
|
|
38
|
-
|
|
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
|
}
|
|
@@ -73,11 +76,28 @@ export declare class EvolutionReplayDriver {
|
|
|
73
76
|
/** V26-05 (v25): plan ids recorded live BEFORE the backfill settled. A
|
|
74
77
|
* plan-applied landing inside the one-shot `loadActivity` read window is
|
|
75
78
|
* recorded live AND persisted into the sidecar the backfill is reading —
|
|
76
|
-
* `backfill()` drops those ids so the event is not counted twice.
|
|
79
|
+
* `backfill()` drops those ids so the event is not counted twice.
|
|
80
|
+
*
|
|
81
|
+
* V27 INS-05: the set is BOUNDED. `backfill()` is the only place that cleared
|
|
82
|
+
* it, so a sidecar load that never succeeded (the inject callback's catch
|
|
83
|
+
* warns and does not retry until the io dependency is replaced) let every
|
|
84
|
+
* live plan id accumulate for the process lifetime. Past
|
|
85
|
+
* PRE_BACKFILL_ID_CAP the oldest ids are dropped: the dedupe window is then
|
|
86
|
+
* finite, and a dropped duplicate can at worst repeat an entry inside the
|
|
87
|
+
* `maxPlans` window instead of growing memory without bound. */
|
|
77
88
|
private readonly preBackfillIds;
|
|
89
|
+
/** Upper bound on {@link EvolutionReplayDriver.preBackfillIds} (V27 INS-05). */
|
|
90
|
+
private static readonly PRE_BACKFILL_ID_CAP;
|
|
78
91
|
private readonly weights;
|
|
79
92
|
constructor(config?: Config, warn?: (message: string) => void);
|
|
80
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;
|
|
81
101
|
/**
|
|
82
102
|
* V25-01 (v25): backfill the leaderboard from the activity sidecar, ONCE
|
|
83
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.
|
|
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.
|
|
35
|
-
"@lmzhen/dsh-evolution-core": "^0.3.
|
|
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.
|
|
44
|
-
"@lmzhen/dsh-evolution-core": "^0.3.
|
|
43
|
+
"@lmzhen/dsh-evolution-activity": "^0.3.69",
|
|
44
|
+
"@lmzhen/dsh-evolution-core": "^0.3.69"
|
|
45
45
|
}
|
|
46
46
|
}
|