dsh-continual-evolve 0.2.0 → 0.4.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.
- package/README.md +83 -371
- package/README.zh.md +84 -235
- package/lib/apply.js +8 -2
- package/lib/approval.d.ts +6 -0
- package/lib/approval.js +9 -1
- package/lib/auto.d.ts +55 -4
- package/lib/auto.js +61 -5
- package/lib/benchmark-command.d.ts +9 -0
- package/lib/benchmark-command.js +333 -0
- package/lib/benchmark.d.ts +70 -0
- package/lib/benchmark.js +107 -1
- package/lib/command.d.ts +3 -0
- package/lib/command.js +62 -441
- package/lib/evaluate.d.ts +7 -0
- package/lib/evaluate.js +22 -7
- package/lib/evolve-event.d.ts +38 -0
- package/lib/evolve-event.js +49 -0
- package/lib/failures.d.ts +39 -0
- package/lib/failures.js +170 -0
- package/lib/fate.d.ts +5 -2
- package/lib/fate.js +13 -8
- package/lib/goal-command.d.ts +7 -0
- package/lib/goal-command.js +37 -0
- package/lib/index.d.ts +51 -25
- package/lib/index.js +33 -1
- package/lib/inject.d.ts +24 -1
- package/lib/inject.js +93 -5
- package/lib/llm-text.d.ts +30 -0
- package/lib/llm-text.js +49 -0
- package/lib/mount-command.d.ts +10 -0
- package/lib/mount-command.js +48 -0
- package/lib/plan.js +5 -0
- package/lib/planner.d.ts +1 -1
- package/lib/planner.js +13 -39
- package/lib/promotion.d.ts +62 -0
- package/lib/promotion.js +102 -0
- package/lib/render.d.ts +1 -3
- package/lib/render.js +0 -4
- package/lib/review.d.ts +4 -1
- package/lib/review.js +10 -38
- package/lib/rollback.d.ts +1 -3
- package/lib/rollback.js +0 -8
- package/lib/score.d.ts +15 -0
- package/lib/score.js +74 -5
- package/lib/service.d.ts +2 -2
- package/lib/service.js +7 -3
- package/lib/skill-render.d.ts +23 -0
- package/lib/skill-render.js +68 -0
- package/lib/skill.d.ts +2 -5
- package/lib/skill.js +2 -29
- package/lib/skillquality.d.ts +1 -2
- package/lib/skillquality.js +2 -2
- package/lib/state.js +6 -1
- package/lib/store.d.ts +1 -3
- package/lib/store.js +0 -7
- package/lib/tool.js +22 -1
- package/lib/types.d.ts +8 -0
- package/lib/usage.d.ts +45 -0
- package/lib/usage.js +115 -0
- package/lib/validate.d.ts +12 -2
- package/lib/validate.js +26 -1
- package/lib/wrapup-command.d.ts +9 -0
- package/lib/wrapup-command.js +212 -0
- package/lib/wrapup.d.ts +29 -15
- package/lib/wrapup.js +69 -42
- package/package.json +10 -8
package/lib/benchmark.js
CHANGED
|
@@ -106,6 +106,8 @@ export function addCase(baseDir, bid, title, statement, rubric, rubricKey) {
|
|
|
106
106
|
// resolveRubricKey) and the dev key here is only a defensive last resort.
|
|
107
107
|
const stored = rubricKey ? encryptRubric(rubric, rubricKey) : encryptRubric(rubric, deriveKey(DEV_RUBRIC_KEY));
|
|
108
108
|
writeFileSync(join(caseDir, "rubric.json"), `${JSON.stringify(stored, null, 2)}\n`, "utf8");
|
|
109
|
+
// A5: initialize case metadata for quality gate.
|
|
110
|
+
saveCaseMeta(baseDir, bid, id, defaultCaseMeta());
|
|
109
111
|
return { id, title: title.trim(), statement, rubric };
|
|
110
112
|
}
|
|
111
113
|
export function listCases(baseDir, bid) {
|
|
@@ -121,7 +123,8 @@ export function listCases(baseDir, bid) {
|
|
|
121
123
|
try {
|
|
122
124
|
const statement = readFileSync(statementPath, "utf8");
|
|
123
125
|
const rubric = JSON.parse(readFileSync(rubricPath, "utf8"));
|
|
124
|
-
|
|
126
|
+
const meta = loadCaseMeta(baseDir, bid, id);
|
|
127
|
+
return { id, title: id, statement, rubric, ...(meta ? { status: meta.status } : {}) };
|
|
125
128
|
}
|
|
126
129
|
catch {
|
|
127
130
|
return undefined;
|
|
@@ -149,6 +152,109 @@ export function loadScoreboard(baseDir, bid) {
|
|
|
149
152
|
export function saveScoreboard(baseDir, bid, board) {
|
|
150
153
|
writeFileSync(join(benchmarkDir(baseDir, bid), "scoreboard.json"), `${JSON.stringify(board, null, 2)}\n`, "utf8");
|
|
151
154
|
}
|
|
155
|
+
// ── Case meta (gap A5: quality gate + calibration history) ────────────
|
|
156
|
+
export function loadCaseMeta(baseDir, bid, cid) {
|
|
157
|
+
const path = join(benchmarkDir(baseDir, bid), "cases", cid, "meta.json");
|
|
158
|
+
if (!existsSync(path))
|
|
159
|
+
return undefined;
|
|
160
|
+
try {
|
|
161
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
export function saveCaseMeta(baseDir, bid, cid, meta) {
|
|
168
|
+
const metaDir = join(benchmarkDir(baseDir, bid), "cases", cid);
|
|
169
|
+
mkdirSync(metaDir, { recursive: true });
|
|
170
|
+
writeFileSync(join(metaDir, "meta.json"), `${JSON.stringify(meta, null, 2)}\n`, "utf8");
|
|
171
|
+
}
|
|
172
|
+
/** List case metas for all cases in a benchmark (missing meta → defaults). */
|
|
173
|
+
export function listCaseMetas(baseDir, bid) {
|
|
174
|
+
const result = new Map();
|
|
175
|
+
const cases = listCases(baseDir, bid);
|
|
176
|
+
for (const c of cases) {
|
|
177
|
+
const meta = loadCaseMeta(baseDir, bid, c.id);
|
|
178
|
+
if (meta) {
|
|
179
|
+
result.set(c.id, meta);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
/** Check whether a case is frozen (immutable). */
|
|
185
|
+
export function isCaseFrozen(baseDir, bid, cid) {
|
|
186
|
+
const meta = loadCaseMeta(baseDir, bid, cid);
|
|
187
|
+
return meta?.status === "frozen";
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Transition a case's lifecycle state. Throws on illegal transitions.
|
|
191
|
+
* draft → calibrating (start pilot)
|
|
192
|
+
* calibrating → draft (abandon calibration)
|
|
193
|
+
* calibrating → frozen (lock baseline)
|
|
194
|
+
*/
|
|
195
|
+
export function transitionCaseStatus(baseDir, bid, cid, to) {
|
|
196
|
+
const meta = loadCaseMeta(baseDir, bid, cid) ?? defaultCaseMeta();
|
|
197
|
+
const from = meta.status;
|
|
198
|
+
const valid = (from === "draft" && to === "calibrating") ||
|
|
199
|
+
(from === "calibrating" && to === "draft") ||
|
|
200
|
+
(from === "calibrating" && to === "frozen");
|
|
201
|
+
if (!valid) {
|
|
202
|
+
throw new Error(`illegal case status transition: ${from} → ${to}`);
|
|
203
|
+
}
|
|
204
|
+
meta.status = to;
|
|
205
|
+
saveCaseMeta(baseDir, bid, cid, meta);
|
|
206
|
+
return meta;
|
|
207
|
+
}
|
|
208
|
+
function defaultCaseMeta() {
|
|
209
|
+
return {
|
|
210
|
+
status: "draft",
|
|
211
|
+
capability: "",
|
|
212
|
+
distinguisher: "",
|
|
213
|
+
shortcuts: "",
|
|
214
|
+
calibrationHistory: [],
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Quality-check a case: mechanical validation without LLM calls.
|
|
219
|
+
* Returns human-readable problems; empty array means the case passes.
|
|
220
|
+
*/
|
|
221
|
+
export function caseCheckProblems(baseDir, bid, cid) {
|
|
222
|
+
const problems = [];
|
|
223
|
+
const statementPath = join(benchmarkDir(baseDir, bid), "cases", cid, "statement.md");
|
|
224
|
+
if (!existsSync(statementPath)) {
|
|
225
|
+
problems.push("statement.md missing");
|
|
226
|
+
return problems;
|
|
227
|
+
}
|
|
228
|
+
const statement = readFileSync(statementPath, "utf8").trim();
|
|
229
|
+
if (statement.length < 20) {
|
|
230
|
+
problems.push(`statement too short (${statement.length} chars, minimum 20)`);
|
|
231
|
+
}
|
|
232
|
+
const rubricPath = join(benchmarkDir(baseDir, bid), "cases", cid, "rubric.json");
|
|
233
|
+
if (!existsSync(rubricPath)) {
|
|
234
|
+
problems.push("rubric.json missing");
|
|
235
|
+
return problems;
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
const raw = readFileSync(rubricPath, "utf8");
|
|
239
|
+
JSON.parse(raw);
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
problems.push("rubric.json is not valid JSON");
|
|
243
|
+
}
|
|
244
|
+
const meta = loadCaseMeta(baseDir, bid, cid);
|
|
245
|
+
if (!meta) {
|
|
246
|
+
problems.push("meta.json missing (run /evolve benchmark casecheck to initialize)");
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
if (!meta.capability)
|
|
250
|
+
problems.push("capability contract is empty");
|
|
251
|
+
if (!meta.distinguisher)
|
|
252
|
+
problems.push("distinguisher is empty");
|
|
253
|
+
if (!meta.shortcuts)
|
|
254
|
+
problems.push("shortcuts annotation is empty");
|
|
255
|
+
}
|
|
256
|
+
return problems;
|
|
257
|
+
}
|
|
152
258
|
export function removeBenchmark(baseDir, bid) {
|
|
153
259
|
const dir = benchmarkDir(baseDir, bid);
|
|
154
260
|
if (existsSync(dir)) {
|
package/lib/command.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import type { Context } from "@deepseek-ai/cordis";
|
|
6
6
|
import type { HarnessEntry, HarnessState, RefinementKind } from "./types.js";
|
|
7
7
|
import type { EvolutionEngine } from "./service.js";
|
|
8
|
+
import type { PromotionPolicy } from "./promotion.js";
|
|
8
9
|
export interface CommandGateOptions {
|
|
9
10
|
requireGlobalApproval: boolean;
|
|
10
11
|
}
|
|
@@ -12,6 +13,8 @@ export interface CommandRuntimeOptions {
|
|
|
12
13
|
rubricKey: Buffer;
|
|
13
14
|
/** When a benchmark decision rejects a candidate, roll the refinement back automatically. */
|
|
14
15
|
autoRollbackOnReject: boolean;
|
|
16
|
+
/** Mechanical promotion guards for wrapup/fate (2026-08-22 policy). */
|
|
17
|
+
promotionPolicy: PromotionPolicy;
|
|
15
18
|
}
|
|
16
19
|
export declare function registerEvolveCommand(ctx: Context, engine: EvolutionEngine, opts: CommandGateOptions, runtime: CommandRuntimeOptions): void;
|
|
17
20
|
/**
|