dsh-continual-evolve 0.11.0 → 0.12.1
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 +42 -115
- package/README.zh.md +33 -93
- package/client/client.js +253 -0
- package/cordis.patch.yml +2 -2
- package/lib/card-routes.d.ts +32 -0
- package/lib/card-routes.js +92 -0
- package/lib/index.d.ts +65 -217
- package/lib/index.js +74 -234
- package/lib/known-workspaces.d.ts +22 -0
- package/lib/known-workspaces.js +42 -0
- package/lib/memory-guide.d.ts +13 -14
- package/lib/memory-guide.js +34 -21
- package/lib/memory-section.d.ts +77 -0
- package/lib/memory-section.js +189 -0
- package/lib/memory-snapshot.d.ts +54 -0
- package/lib/memory-snapshot.js +125 -0
- package/package.json +8 -17
- package/lib/apply.d.ts +0 -22
- package/lib/apply.js +0 -157
- package/lib/approval.d.ts +0 -73
- package/lib/approval.js +0 -127
- package/lib/audit-log.d.ts +0 -19
- package/lib/audit-log.js +0 -52
- package/lib/auto.d.ts +0 -236
- package/lib/auto.js +0 -773
- package/lib/autocase.d.ts +0 -38
- package/lib/autocase.js +0 -76
- package/lib/benchmark-command.d.ts +0 -9
- package/lib/benchmark-command.js +0 -357
- package/lib/benchmark.d.ts +0 -151
- package/lib/benchmark.js +0 -250
- package/lib/command-util.d.ts +0 -70
- package/lib/command-util.js +0 -123
- package/lib/command.d.ts +0 -13
- package/lib/command.js +0 -134
- package/lib/consolidate.d.ts +0 -90
- package/lib/consolidate.js +0 -180
- package/lib/copy.d.ts +0 -37
- package/lib/copy.js +0 -58
- package/lib/declines.d.ts +0 -103
- package/lib/declines.js +0 -179
- package/lib/evaluate.d.ts +0 -74
- package/lib/evaluate.js +0 -271
- package/lib/evolve-event.d.ts +0 -40
- package/lib/evolve-event.js +0 -60
- package/lib/extraction-phase.d.ts +0 -132
- package/lib/extraction-phase.js +0 -236
- package/lib/failures.d.ts +0 -42
- package/lib/failures.js +0 -171
- package/lib/fate.d.ts +0 -130
- package/lib/fate.js +0 -350
- package/lib/goal-command.d.ts +0 -7
- package/lib/goal-command.js +0 -37
- package/lib/goal.d.ts +0 -72
- package/lib/goal.js +0 -72
- package/lib/inject.d.ts +0 -90
- package/lib/inject.js +0 -164
- package/lib/injection-caps.d.ts +0 -4
- package/lib/injection-caps.js +0 -4
- package/lib/injection-directory.d.ts +0 -29
- package/lib/injection-directory.js +0 -78
- package/lib/injection-rank.d.ts +0 -85
- package/lib/injection-rank.js +0 -161
- package/lib/listener.d.ts +0 -45
- package/lib/listener.js +0 -199
- package/lib/llm-text.d.ts +0 -104
- package/lib/llm-text.js +0 -140
- package/lib/logfile.d.ts +0 -71
- package/lib/logfile.js +0 -159
- package/lib/maintenance-commands.d.ts +0 -23
- package/lib/maintenance-commands.js +0 -136
- package/lib/memory-agent.d.ts +0 -93
- package/lib/memory-agent.js +0 -300
- package/lib/memory-apply.d.ts +0 -44
- package/lib/memory-apply.js +0 -202
- package/lib/memory-benchmark.d.ts +0 -76
- package/lib/memory-benchmark.js +0 -170
- package/lib/memory-index.d.ts +0 -114
- package/lib/memory-index.js +0 -197
- package/lib/memory-manifest.d.ts +0 -16
- package/lib/memory-manifest.js +0 -70
- package/lib/message-source.d.ts +0 -23
- package/lib/message-source.js +0 -12
- package/lib/mount-command.d.ts +0 -10
- package/lib/mount-command.js +0 -48
- package/lib/mount.d.ts +0 -42
- package/lib/mount.js +0 -212
- package/lib/notify.d.ts +0 -48
- package/lib/notify.js +0 -57
- package/lib/plan-command.d.ts +0 -12
- package/lib/plan-command.js +0 -38
- package/lib/plan.d.ts +0 -16
- package/lib/plan.js +0 -126
- package/lib/planner.d.ts +0 -61
- package/lib/planner.js +0 -144
- package/lib/pool.d.ts +0 -7
- package/lib/pool.js +0 -25
- package/lib/prefix-cache.d.ts +0 -79
- package/lib/prefix-cache.js +0 -168
- package/lib/project.d.ts +0 -28
- package/lib/project.js +0 -66
- package/lib/projection.d.ts +0 -22
- package/lib/projection.js +0 -112
- package/lib/promotion.d.ts +0 -94
- package/lib/promotion.js +0 -171
- package/lib/recall.d.ts +0 -85
- package/lib/recall.js +0 -142
- package/lib/record-language.d.ts +0 -85
- package/lib/record-language.js +0 -152
- package/lib/render.d.ts +0 -13
- package/lib/render.js +0 -80
- package/lib/review-scheduler.d.ts +0 -38
- package/lib/review-scheduler.js +0 -183
- package/lib/review.d.ts +0 -60
- package/lib/review.js +0 -145
- package/lib/rollback.d.ts +0 -9
- package/lib/rollback.js +0 -68
- package/lib/rubric.d.ts +0 -29
- package/lib/rubric.js +0 -119
- package/lib/runtime-commands.d.ts +0 -14
- package/lib/runtime-commands.js +0 -115
- package/lib/runtime.d.ts +0 -24
- package/lib/runtime.js +0 -87
- package/lib/score.d.ts +0 -64
- package/lib/score.js +0 -191
- package/lib/search.d.ts +0 -83
- package/lib/search.js +0 -136
- package/lib/service.d.ts +0 -63
- package/lib/service.js +0 -253
- package/lib/skill-render.d.ts +0 -23
- package/lib/skill-render.js +0 -69
- package/lib/skill.d.ts +0 -15
- package/lib/skill.js +0 -80
- package/lib/skillquality.d.ts +0 -85
- package/lib/skillquality.js +0 -320
- package/lib/source.d.ts +0 -30
- package/lib/source.js +0 -43
- package/lib/state.d.ts +0 -26
- package/lib/state.js +0 -151
- package/lib/store.d.ts +0 -61
- package/lib/store.js +0 -164
- package/lib/token-usage.d.ts +0 -68
- package/lib/token-usage.js +0 -211
- package/lib/tool.d.ts +0 -34
- package/lib/tool.js +0 -320
- package/lib/turn-snapshot.d.ts +0 -78
- package/lib/turn-snapshot.js +0 -252
- package/lib/types.d.ts +0 -218
- package/lib/types.js +0 -133
- package/lib/usage.d.ts +0 -36
- package/lib/usage.js +0 -98
- package/lib/validate.d.ts +0 -28
- package/lib/validate.js +0 -181
- package/lib/wrapup-candidates.d.ts +0 -127
- package/lib/wrapup-candidates.js +0 -161
- package/lib/wrapup-command.d.ts +0 -10
- package/lib/wrapup-command.js +0 -243
- package/lib/wrapup-proposals.d.ts +0 -101
- package/lib/wrapup-proposals.js +0 -281
- package/lib/wrapup.d.ts +0 -56
- package/lib/wrapup.js +0 -105
package/lib/autocase.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/** The dedicated container benchmark every auto-case lands in (sanitizeId-safe). */
|
|
2
|
-
export declare const AUTO_CASE_BENCHMARK_ID = "auto_regression";
|
|
3
|
-
/** Which failed-evolution trigger produced the capture. */
|
|
4
|
-
export type AutoCaseSource = "benchmark_rejection" | "gate_no_consent";
|
|
5
|
-
export interface AutoCaseInput {
|
|
6
|
-
baseDir: string;
|
|
7
|
-
/**
|
|
8
|
-
* Resolved rubric key — captures must decrypt under the installation's
|
|
9
|
-
* real key. Omitting it silently encrypts with the dev fallback, making
|
|
10
|
-
* the scaffold unreadable to the real key; callers resolve once and pass.
|
|
11
|
-
*/
|
|
12
|
-
rubricKey?: Buffer | undefined;
|
|
13
|
-
source: AutoCaseSource;
|
|
14
|
-
sessionId?: string | undefined;
|
|
15
|
-
/** One line for what was being attempted (candidate label / proposal summary). */
|
|
16
|
-
summary: string;
|
|
17
|
-
/** Machine-captured failure reasons (decision reasons / gate rationale). */
|
|
18
|
-
reasons: readonly string[];
|
|
19
|
-
/** Refinement id when the attempt produced one (e.g. a rolled-back candidate). */
|
|
20
|
-
refinementId?: string | undefined;
|
|
21
|
-
now?: number | undefined;
|
|
22
|
-
}
|
|
23
|
-
export interface AutoCaseCapture {
|
|
24
|
-
bid: string;
|
|
25
|
-
caseId: string;
|
|
26
|
-
}
|
|
27
|
-
/** The draft statement: a structured scaffold, not an evaluable task yet. */
|
|
28
|
-
export declare function renderAutoCaseStatement(input: AutoCaseInput, stamp: string): string;
|
|
29
|
-
/** The draft rubric: explicitly not scoreable until a human rewrites it. */
|
|
30
|
-
export declare function renderAutoCaseRubric(input: AutoCaseInput): string;
|
|
31
|
-
/**
|
|
32
|
-
* Capture one failed evolution attempt as a draft case in the container
|
|
33
|
-
* benchmark, creating the container on first use. Id uniqueness comes from
|
|
34
|
-
* the millisecond stamp; two captures in the same millisecond throw (the
|
|
35
|
-
* caller's containment turns that into a warning, never a lost trigger).
|
|
36
|
-
*/
|
|
37
|
-
export declare function captureAutoCase(input: AutoCaseInput): AutoCaseCapture;
|
|
38
|
-
//# sourceMappingURL=autocase.d.ts.map
|
package/lib/autocase.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-case capture (P1, 2026-08-28): failed evolution attempts become DRAFT
|
|
3
|
-
* benchmark cases — regression assets for the benchmark loop instead of
|
|
4
|
-
* discarded failure notes.
|
|
5
|
-
*
|
|
6
|
-
* Captures land in a dedicated container benchmark (auto-regression), NEVER
|
|
7
|
-
* in a user benchmark: a benchmark run evaluates every case in its container
|
|
8
|
-
* without a status filter, and an auto-case's rubric is a mechanical scaffold
|
|
9
|
-
* that must never be scored. Humans promote a capture into a real benchmark
|
|
10
|
-
* by re-authoring statement and rubric there, then casecheck → pilot →
|
|
11
|
-
* freeze. The container benchmark keeps the staging area visible and
|
|
12
|
-
* rollback-free (no engine involvement anywhere).
|
|
13
|
-
*
|
|
14
|
-
* No LLM call: the capture is deterministic. Callers own containment — a
|
|
15
|
-
* failed capture must never break the trigger path (benchmark run, gate).
|
|
16
|
-
*/
|
|
17
|
-
import { addCase, createBenchmark, loadBenchmark } from "./benchmark.js";
|
|
18
|
-
/** The dedicated container benchmark every auto-case lands in (sanitizeId-safe). */
|
|
19
|
-
export const AUTO_CASE_BENCHMARK_ID = "auto_regression";
|
|
20
|
-
/** Id-safe compact timestamp (20260828T131934000Z style), unique per capture. */
|
|
21
|
-
function idStamp(now) {
|
|
22
|
-
return new Date(now)
|
|
23
|
-
.toISOString()
|
|
24
|
-
.replace(/[-:]/g, "")
|
|
25
|
-
.replace(".", "")
|
|
26
|
-
.replace("Z", "Z");
|
|
27
|
-
}
|
|
28
|
-
/** The draft statement: a structured scaffold, not an evaluable task yet. */
|
|
29
|
-
export function renderAutoCaseStatement(input, stamp) {
|
|
30
|
-
const lines = [
|
|
31
|
-
"# Auto-generated regression scaffold",
|
|
32
|
-
"",
|
|
33
|
-
`- source: ${input.source}`,
|
|
34
|
-
`- captured: ${stamp}`,
|
|
35
|
-
`- session: ${input.sessionId ?? "(unknown)"}`,
|
|
36
|
-
...(input.refinementId ? [`- refinement: ${input.refinementId}`] : []),
|
|
37
|
-
`- attempted: ${input.summary}`,
|
|
38
|
-
"- failure reasons:",
|
|
39
|
-
...(input.reasons.length > 0 ? input.reasons.map((reason) => ` - ${reason}`) : [" - (none captured)"]),
|
|
40
|
-
"",
|
|
41
|
-
"This case was captured mechanically from a failed evolution attempt.",
|
|
42
|
-
"It lives in the auto-regression container and never enters a user",
|
|
43
|
-
"benchmark automatically. To promote it: re-author the statement and",
|
|
44
|
-
"rubric in a real benchmark, then casecheck → pilot → freeze.",
|
|
45
|
-
];
|
|
46
|
-
return `${lines.join("\n")}\n`;
|
|
47
|
-
}
|
|
48
|
-
/** The draft rubric: explicitly not scoreable until a human rewrites it. */
|
|
49
|
-
export function renderAutoCaseRubric(input) {
|
|
50
|
-
return [
|
|
51
|
-
"Draft scaffold — the real rubric is authored at calibration time.",
|
|
52
|
-
`Scoring signal captured from the failure: ${input.reasons.join("; ") || "(none)"}.`,
|
|
53
|
-
"Scoring against this scaffold is meaningless until a human rewrites it;",
|
|
54
|
-
"the case stays in the auto-regression container and out of real runs.",
|
|
55
|
-
].join("\n");
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Capture one failed evolution attempt as a draft case in the container
|
|
59
|
-
* benchmark, creating the container on first use. Id uniqueness comes from
|
|
60
|
-
* the millisecond stamp; two captures in the same millisecond throw (the
|
|
61
|
-
* caller's containment turns that into a warning, never a lost trigger).
|
|
62
|
-
*/
|
|
63
|
-
export function captureAutoCase(input) {
|
|
64
|
-
if (!loadBenchmark(input.baseDir, AUTO_CASE_BENCHMARK_ID)) {
|
|
65
|
-
createBenchmark(input.baseDir, {
|
|
66
|
-
title: AUTO_CASE_BENCHMARK_ID,
|
|
67
|
-
description: "Draft regression scaffolds captured mechanically from failed evolution attempts. Not evaluated; promote captures into a real benchmark by hand (re-author statement/rubric, then casecheck → pilot → freeze).",
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
const stamp = idStamp(input.now ?? Date.now());
|
|
71
|
-
// Stamp first: sanitizeId truncates to 40 chars, and the stamp must
|
|
72
|
-
// survive the truncation for per-millisecond capture uniqueness.
|
|
73
|
-
const added = addCase(input.baseDir, AUTO_CASE_BENCHMARK_ID, `auto ${stamp} ${input.source}`, renderAutoCaseStatement(input, stamp), renderAutoCaseRubric(input), input.rubricKey);
|
|
74
|
-
return { bid: AUTO_CASE_BENCHMARK_ID, caseId: added.id };
|
|
75
|
-
}
|
|
76
|
-
//# sourceMappingURL=autocase.js.map
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `/evolve benchmark` subcommand handler. Extracted from command.ts (P2-2).
|
|
3
|
-
*/
|
|
4
|
-
import type { Context } from "@deepseek-ai/cordis";
|
|
5
|
-
import type { CommandInvocation, CommandResult } from "@deepseek-ai/dsh-commands";
|
|
6
|
-
import type { EvolutionEngine } from "./service.js";
|
|
7
|
-
import type { CommandRuntimeOptions } from "./command-util.js";
|
|
8
|
-
export declare function executeBenchmarkCommand(ctx: Context, engine: EvolutionEngine, invocation: CommandInvocation, rest: string[], runtime: CommandRuntimeOptions): Promise<CommandResult>;
|
|
9
|
-
//# sourceMappingURL=benchmark-command.d.ts.map
|
package/lib/benchmark-command.js
DELETED
|
@@ -1,357 +0,0 @@
|
|
|
1
|
-
import { formatHarnessStateForPrompt } from "./render.js";
|
|
2
|
-
import { stripAngleBrackets } from "./command-util.js";
|
|
3
|
-
import { addCase, caseCheckProblems, createBenchmark, listBenchmarks, listCases, loadBenchmark, loadCaseMeta, loadScoreboard, rollbackRejectedCandidate, saveCaseMeta, saveScoreboard, transitionCaseStatus } from "./benchmark.js";
|
|
4
|
-
import { AUTO_CASE_BENCHMARK_ID, captureAutoCase } from "./autocase.js";
|
|
5
|
-
import { decide, decisionReport, entryFromCells, flagMaterialDrift } from "./score.js";
|
|
6
|
-
import { evaluateState } from "./evaluate.js";
|
|
7
|
-
function success(text) {
|
|
8
|
-
return { kind: "success", text };
|
|
9
|
-
}
|
|
10
|
-
function error(text) {
|
|
11
|
-
return { kind: "error", text };
|
|
12
|
-
}
|
|
13
|
-
function parsePositiveInt(value, what) {
|
|
14
|
-
const n = Number(value);
|
|
15
|
-
if (!Number.isInteger(n) || n < 1) {
|
|
16
|
-
throw new Error(`${what} must be a positive integer, got "${value}"`);
|
|
17
|
-
}
|
|
18
|
-
return n;
|
|
19
|
-
}
|
|
20
|
-
/** " (N failed)" suffix when an evaluation entry carries failed cells. */
|
|
21
|
-
function failedTextOf(entry) {
|
|
22
|
-
const failed = entry.cells.filter((cell) => cell.status === "failed").length;
|
|
23
|
-
return failed > 0 ? ` (${failed} failed)` : "";
|
|
24
|
-
}
|
|
25
|
-
const BENCHMARK_USAGE = `Usage:
|
|
26
|
-
/evolve benchmark new <title> create a benchmark (runs=1)
|
|
27
|
-
/evolve benchmark add-case <bid> <title> <statement> <rubric>
|
|
28
|
-
/evolve benchmark list list benchmarks + reference status
|
|
29
|
-
/evolve benchmark status <bid> show scoreboard + decisions
|
|
30
|
-
/evolve benchmark reset <bid> clear the scoreboard (fresh reference)
|
|
31
|
-
/evolve benchmark run <bid> evaluate current state as the reference
|
|
32
|
-
/evolve benchmark run <bid> candidate <refinementId> evaluate the post-refinement state and decide
|
|
33
|
-
/evolve benchmark casecheck <bid> quality-gate check all cases
|
|
34
|
-
/evolve benchmark pilot <bid> <cid> single pilot run for calibration
|
|
35
|
-
/evolve benchmark freeze <bid> <cid> freeze a case as formal baseline
|
|
36
|
-
/evolve benchmark meta <bid> <cid> [field value ...] set case metadata (capability/distinguisher/shortcuts)`;
|
|
37
|
-
export async function executeBenchmarkCommand(ctx, engine, invocation, rest, runtime) {
|
|
38
|
-
const sub = rest[0] ?? "";
|
|
39
|
-
const args = rest.slice(1);
|
|
40
|
-
const sessionId = invocation.agent.id;
|
|
41
|
-
const baseDir = engine.baseDir;
|
|
42
|
-
switch (sub) {
|
|
43
|
-
case "":
|
|
44
|
-
case "help":
|
|
45
|
-
return success(BENCHMARK_USAGE);
|
|
46
|
-
case "new": {
|
|
47
|
-
const title = args[0] ?? "";
|
|
48
|
-
if (!title) {
|
|
49
|
-
return error(`benchmark new requires a title.\n${BENCHMARK_USAGE}`);
|
|
50
|
-
}
|
|
51
|
-
const runs = args[1] !== undefined ? parsePositiveInt(args[1], "runs") : undefined;
|
|
52
|
-
const definition = createBenchmark(baseDir, { title, ...(runs !== undefined ? { runs } : {}) });
|
|
53
|
-
return success(`benchmark ${definition.id} created (runs=${definition.runs}, passThreshold=${definition.passThreshold})\nAdd cases with: /evolve benchmark add-case ${definition.id} "<title>" "<statement>" "<rubric>"`);
|
|
54
|
-
}
|
|
55
|
-
case "list": {
|
|
56
|
-
const benchmarks = listBenchmarks(baseDir);
|
|
57
|
-
if (benchmarks.length === 0) {
|
|
58
|
-
return success("(no benchmarks yet — use /evolve benchmark new <title>)");
|
|
59
|
-
}
|
|
60
|
-
const lines = benchmarks.map((b) => {
|
|
61
|
-
const cases = listCases(baseDir, b.id);
|
|
62
|
-
const board = loadScoreboard(baseDir, b.id);
|
|
63
|
-
const ref = board.reference ? ` ref=${board.reference.overall ?? "?"}` : " no-reference";
|
|
64
|
-
return `- ${b.id} (${cases.length} cases, runs=${b.runs})${ref}`;
|
|
65
|
-
});
|
|
66
|
-
return success(lines.join("\n"));
|
|
67
|
-
}
|
|
68
|
-
case "add-case": {
|
|
69
|
-
const bid = stripAngleBrackets(args[0] ?? "");
|
|
70
|
-
const title = args[1] ?? "";
|
|
71
|
-
const statement = args[2] ?? "";
|
|
72
|
-
const rubric = args[3] ?? "";
|
|
73
|
-
if (!bid || !title || !statement || !rubric) {
|
|
74
|
-
return error(`benchmark add-case needs <bid> <title> <statement> <rubric>.\n${BENCHMARK_USAGE}`);
|
|
75
|
-
}
|
|
76
|
-
if (!loadBenchmark(baseDir, bid)) {
|
|
77
|
-
return error(`benchmark ${bid} not found`);
|
|
78
|
-
}
|
|
79
|
-
const caseItem = addCase(baseDir, bid, title, statement, rubric, runtime.rubricKey);
|
|
80
|
-
return success(`case ${caseItem.id} added to ${bid} (status: draft)`);
|
|
81
|
-
}
|
|
82
|
-
case "reset": {
|
|
83
|
-
const bid = stripAngleBrackets(args[0] ?? "");
|
|
84
|
-
if (!bid) {
|
|
85
|
-
return error(`benchmark reset needs a <bid>.\n${BENCHMARK_USAGE}`);
|
|
86
|
-
}
|
|
87
|
-
if (!loadBenchmark(baseDir, bid)) {
|
|
88
|
-
return error(`benchmark ${bid} not found`);
|
|
89
|
-
}
|
|
90
|
-
saveScoreboard(baseDir, bid, { candidates: [], decisions: [] });
|
|
91
|
-
return success(`scoreboard reset for ${bid} — run /evolve benchmark run ${bid} to record a fresh reference`);
|
|
92
|
-
}
|
|
93
|
-
case "status": {
|
|
94
|
-
const bid = stripAngleBrackets(args[0] ?? "");
|
|
95
|
-
const board = loadScoreboard(baseDir, bid);
|
|
96
|
-
const lines = [];
|
|
97
|
-
if (board.reference) {
|
|
98
|
-
lines.push(`reference "${board.reference.label}": overall=${board.reference.overall ?? "?"} cells=${board.reference.cells.length}${failedTextOf(board.reference)}`);
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
lines.push("(no reference evaluation yet)");
|
|
102
|
-
}
|
|
103
|
-
for (const c of board.candidates) {
|
|
104
|
-
lines.push(`candidate "${c.label}": overall=${c.overall ?? "?"} cells=${c.cells.length}${failedTextOf(c)}${c.refinementId ? ` (${c.refinementId})` : ""}`);
|
|
105
|
-
}
|
|
106
|
-
for (const d of board.decisions) {
|
|
107
|
-
lines.push(`decision: ${d.accepted ? "ACCEPTED" : "rejected"} ${d.candidateLabel} — ${d.reasons.join("; ") || "ok"}`);
|
|
108
|
-
}
|
|
109
|
-
return success(lines.join("\n"));
|
|
110
|
-
}
|
|
111
|
-
case "run": {
|
|
112
|
-
const bid = stripAngleBrackets(args[0] ?? "");
|
|
113
|
-
const candidateId = args.includes("candidate") ? stripAngleBrackets(args[args.indexOf("candidate") + 1] ?? "") : undefined;
|
|
114
|
-
const definition = loadBenchmark(baseDir, bid);
|
|
115
|
-
if (!definition) {
|
|
116
|
-
return error(`benchmark ${bid} not found`);
|
|
117
|
-
}
|
|
118
|
-
const cases = listCases(baseDir, bid);
|
|
119
|
-
if (cases.length === 0) {
|
|
120
|
-
return error(`benchmark ${bid} has no cases — use /evolve benchmark add-case`);
|
|
121
|
-
}
|
|
122
|
-
const board = loadScoreboard(baseDir, bid);
|
|
123
|
-
const label = candidateId ? `candidate:${candidateId}` : "reference";
|
|
124
|
-
if (!candidateId && board.reference) {
|
|
125
|
-
return error(`reference already evaluated (${board.reference.overall ?? "?"}); evaluate a candidate instead: /evolve benchmark run ${bid} candidate <refinementId>`);
|
|
126
|
-
}
|
|
127
|
-
const overview = formatHarnessStateForPrompt(engine.load("local", sessionId));
|
|
128
|
-
const outcome = await evaluateState(ctx, invocation.agent, {
|
|
129
|
-
cases,
|
|
130
|
-
rubricKey: runtime.rubricKey,
|
|
131
|
-
runs: definition.runs,
|
|
132
|
-
passThreshold: definition.passThreshold,
|
|
133
|
-
harnessOverview: overview,
|
|
134
|
-
label,
|
|
135
|
-
signal: invocation.signal,
|
|
136
|
-
});
|
|
137
|
-
// Gap A3 (version_changed semantics): when a reference exists, re-check
|
|
138
|
-
// the candidate's cells for material drift — a case whose statement/rubric
|
|
139
|
-
// hash differs from the reference run is re-marked failed (never counted
|
|
140
|
-
// as a score, can reject the round via the failure-cell protocol).
|
|
141
|
-
const cells = candidateId && board.reference ? flagMaterialDrift(board.reference, outcome.cells) : outcome.cells;
|
|
142
|
-
const entry = entryFromCells(label, cells, candidateId);
|
|
143
|
-
const failedCells = cells.filter((cell) => cell.status === "failed").length;
|
|
144
|
-
const lines = [
|
|
145
|
-
`evaluation "${label}": ${outcome.cells.length} cells${failedCells > 0 ? `, ${failedCells} failed` : ""}, overall=${entry.overall ?? "?"}`,
|
|
146
|
-
...Object.entries(entry.aggregate)
|
|
147
|
-
// totalDurationMs is metadata, not a case (FAQ #11: the same
|
|
148
|
-
// leak class decide/decisionReport already fixed — this
|
|
149
|
-
// display path was the remaining one; review audit S4).
|
|
150
|
-
.filter(([key]) => key !== "overall" && key !== "failed" && key !== "total" && key !== "totalDurationMs")
|
|
151
|
-
.map(([key, value]) => ` ${key}: ${value ?? "?"}`),
|
|
152
|
-
];
|
|
153
|
-
if (failedCells > 0) {
|
|
154
|
-
for (const cell of cells.filter((cell) => cell.status === "failed")) {
|
|
155
|
-
lines.push(` [failed] ${cell.caseId} r${cell.run}: ${cell.notes}`);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
if (candidateId) {
|
|
159
|
-
if (!board.reference) {
|
|
160
|
-
lines.push("(no reference yet — this run only recorded the candidate)");
|
|
161
|
-
board.candidates.push(entry);
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
const decision = decide(board.reference, entry, {
|
|
165
|
-
passThreshold: definition.passThreshold,
|
|
166
|
-
regressionTolerance: 0,
|
|
167
|
-
maxFailedCells: 0,
|
|
168
|
-
});
|
|
169
|
-
board.candidates.push(entry);
|
|
170
|
-
board.decisions.push({
|
|
171
|
-
candidateLabel: label,
|
|
172
|
-
refinementId: candidateId,
|
|
173
|
-
accepted: decision.accepted,
|
|
174
|
-
reasons: decision.reasons,
|
|
175
|
-
createdAt: new Date().toISOString(),
|
|
176
|
-
});
|
|
177
|
-
lines.push(...decisionReport(board.reference, entry, decision));
|
|
178
|
-
if (!decision.accepted) {
|
|
179
|
-
lines.push(`Consider rolling back the candidate: /evolve rollback <${candidateId}>`);
|
|
180
|
-
if (runtime.autoRollbackOnReject) {
|
|
181
|
-
const outcome = rollbackRejectedCandidate(engine, sessionId, candidateId);
|
|
182
|
-
lines.push(outcome.message);
|
|
183
|
-
}
|
|
184
|
-
// P1 auto-case capture: the rejected candidate becomes a
|
|
185
|
-
// draft regression scaffold. Contained — a failed capture
|
|
186
|
-
// must never break the benchmark run's report.
|
|
187
|
-
if (runtime.autoCase) {
|
|
188
|
-
try {
|
|
189
|
-
const captured = captureAutoCase({
|
|
190
|
-
baseDir,
|
|
191
|
-
rubricKey: runtime.rubricKey,
|
|
192
|
-
source: "benchmark_rejection",
|
|
193
|
-
sessionId,
|
|
194
|
-
summary: `${bid} candidate ${candidateId}`,
|
|
195
|
-
reasons: decision.reasons,
|
|
196
|
-
refinementId: candidateId,
|
|
197
|
-
});
|
|
198
|
-
lines.push(`auto-case captured: ${AUTO_CASE_BENCHMARK_ID}/${captured.caseId} (draft — promote manually if it earns a place)`);
|
|
199
|
-
}
|
|
200
|
-
catch (cause) {
|
|
201
|
-
ctx.logger("continual-evolve").warn(`auto-case capture failed: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
board.reference = entry;
|
|
209
|
-
lines.push("reference evaluation recorded as the baseline");
|
|
210
|
-
}
|
|
211
|
-
saveScoreboard(baseDir, bid, board);
|
|
212
|
-
return success(lines.join("\n"));
|
|
213
|
-
}
|
|
214
|
-
case "casecheck": {
|
|
215
|
-
const bid = stripAngleBrackets(args[0] ?? "");
|
|
216
|
-
if (!bid) {
|
|
217
|
-
return error(`benchmark casecheck needs a <bid>.\n${BENCHMARK_USAGE}`);
|
|
218
|
-
}
|
|
219
|
-
const definition = loadBenchmark(baseDir, bid);
|
|
220
|
-
if (!definition) {
|
|
221
|
-
return error(`benchmark ${bid} not found`);
|
|
222
|
-
}
|
|
223
|
-
const cases = listCases(baseDir, bid);
|
|
224
|
-
if (cases.length === 0) {
|
|
225
|
-
return error(`benchmark ${bid} has no cases`);
|
|
226
|
-
}
|
|
227
|
-
const lines = [];
|
|
228
|
-
let totalProblems = 0;
|
|
229
|
-
for (const c of cases) {
|
|
230
|
-
const problems = caseCheckProblems(baseDir, bid, c.id);
|
|
231
|
-
const meta = loadCaseMeta(baseDir, bid, c.id);
|
|
232
|
-
const status = meta?.status ?? "draft";
|
|
233
|
-
if (problems.length === 0) {
|
|
234
|
-
lines.push(` ${c.id} [${status}] ✓`);
|
|
235
|
-
}
|
|
236
|
-
else {
|
|
237
|
-
lines.push(` ${c.id} [${status}] ✗ (${problems.length} problem${problems.length > 1 ? "s" : ""}):`);
|
|
238
|
-
for (const p of problems) {
|
|
239
|
-
lines.push(` - ${p}`);
|
|
240
|
-
}
|
|
241
|
-
totalProblems += problems.length;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
const verdict = totalProblems === 0 ? "✓ all cases pass quality gate" : `✗ ${totalProblems} problem${totalProblems > 1 ? "s" : ""} found`;
|
|
245
|
-
return success(`casecheck ${bid}: ${verdict}\n${cases.length} cases checked\n${lines.join("\n")}`);
|
|
246
|
-
}
|
|
247
|
-
case "pilot": {
|
|
248
|
-
const bid = stripAngleBrackets(args[0] ?? "");
|
|
249
|
-
const cid = stripAngleBrackets(args[1] ?? "");
|
|
250
|
-
if (!bid || !cid) {
|
|
251
|
-
return error(`benchmark pilot needs <bid> <cid>.\n${BENCHMARK_USAGE}`);
|
|
252
|
-
}
|
|
253
|
-
const definition = loadBenchmark(baseDir, bid);
|
|
254
|
-
if (!definition) {
|
|
255
|
-
return error(`benchmark ${bid} not found`);
|
|
256
|
-
}
|
|
257
|
-
const cases = listCases(baseDir, bid);
|
|
258
|
-
const target = cases.find((c) => c.id === cid);
|
|
259
|
-
if (!target) {
|
|
260
|
-
return error(`case ${cid} not found in ${bid}`);
|
|
261
|
-
}
|
|
262
|
-
// Transition to calibrating if currently draft.
|
|
263
|
-
const meta = loadCaseMeta(baseDir, bid, cid);
|
|
264
|
-
if (meta?.status === "frozen") {
|
|
265
|
-
return error(`case ${cid} is frozen and cannot be calibrated`);
|
|
266
|
-
}
|
|
267
|
-
if (meta?.status !== "calibrating") {
|
|
268
|
-
transitionCaseStatus(baseDir, bid, cid, "calibrating");
|
|
269
|
-
}
|
|
270
|
-
// Run a single evaluation on just this case (1 run).
|
|
271
|
-
const overview = formatHarnessStateForPrompt(engine.load("local", sessionId));
|
|
272
|
-
const outcome = await evaluateState(ctx, invocation.agent, {
|
|
273
|
-
cases: [target],
|
|
274
|
-
rubricKey: runtime.rubricKey,
|
|
275
|
-
runs: 1,
|
|
276
|
-
passThreshold: definition.passThreshold,
|
|
277
|
-
harnessOverview: overview,
|
|
278
|
-
label: `pilot:${cid}`,
|
|
279
|
-
signal: invocation.signal,
|
|
280
|
-
});
|
|
281
|
-
const cell = outcome.cells[0];
|
|
282
|
-
const scoreText = cell?.status === "ok" ? `${cell.score} (${cell.passed ? "passed" : "below threshold"})` : `failed: ${cell?.notes ?? "unknown"}`;
|
|
283
|
-
// Record in calibration history.
|
|
284
|
-
const updatedMeta = loadCaseMeta(baseDir, bid, cid) ?? { status: "calibrating", capability: "", distinguisher: "", shortcuts: "", calibrationHistory: [] };
|
|
285
|
-
// Older or externally-written meta.json may lack the history array.
|
|
286
|
-
updatedMeta.calibrationHistory ??= [];
|
|
287
|
-
updatedMeta.calibrationHistory.push({
|
|
288
|
-
runAt: new Date().toISOString(),
|
|
289
|
-
score: cell?.status === "ok" ? cell.score : 0,
|
|
290
|
-
passed: cell?.passed ?? false,
|
|
291
|
-
notes: cell?.notes ?? "",
|
|
292
|
-
modified: false,
|
|
293
|
-
});
|
|
294
|
-
saveCaseMeta(baseDir, bid, cid, updatedMeta);
|
|
295
|
-
const lines = [
|
|
296
|
-
`pilot ${cid}: ${scoreText}`,
|
|
297
|
-
`status: calibrating`,
|
|
298
|
-
`calibration runs: ${updatedMeta.calibrationHistory.length}`,
|
|
299
|
-
];
|
|
300
|
-
if (cell?.status === "ok" && cell.sessionId) {
|
|
301
|
-
lines.push(`session: ${cell.sessionId}`);
|
|
302
|
-
}
|
|
303
|
-
lines.push(`next: set meta fields, then /evolve benchmark freeze ${bid} ${cid}`);
|
|
304
|
-
return success(lines.join("\n"));
|
|
305
|
-
}
|
|
306
|
-
case "freeze": {
|
|
307
|
-
const bid = stripAngleBrackets(args[0] ?? "");
|
|
308
|
-
const cid = stripAngleBrackets(args[1] ?? "");
|
|
309
|
-
if (!bid || !cid) {
|
|
310
|
-
return error(`benchmark freeze needs <bid> <cid>.\n${BENCHMARK_USAGE}`);
|
|
311
|
-
}
|
|
312
|
-
const definition = loadBenchmark(baseDir, bid);
|
|
313
|
-
if (!definition) {
|
|
314
|
-
return error(`benchmark ${bid} not found`);
|
|
315
|
-
}
|
|
316
|
-
const meta = loadCaseMeta(baseDir, bid, cid);
|
|
317
|
-
if (!meta) {
|
|
318
|
-
return error(`case ${cid} not found in ${bid}`);
|
|
319
|
-
}
|
|
320
|
-
if (meta.status === "frozen") {
|
|
321
|
-
return error(`case ${cid} is already frozen`);
|
|
322
|
-
}
|
|
323
|
-
// Require quality check to pass before freezing.
|
|
324
|
-
const problems = caseCheckProblems(baseDir, bid, cid);
|
|
325
|
-
if (problems.length > 0) {
|
|
326
|
-
return error(`case ${cid} has ${problems.length} quality problem${problems.length > 1 ? "s" : ""}:\n${problems.map((p) => ` - ${p}`).join("\n")}\nFix these before freezing.`);
|
|
327
|
-
}
|
|
328
|
-
transitionCaseStatus(baseDir, bid, cid, "frozen");
|
|
329
|
-
return success(`case ${cid} frozen as formal baseline (immutable)`);
|
|
330
|
-
}
|
|
331
|
-
case "meta": {
|
|
332
|
-
const bid = stripAngleBrackets(args[0] ?? "");
|
|
333
|
-
const cid = stripAngleBrackets(args[1] ?? "");
|
|
334
|
-
const field = args[2] ?? "";
|
|
335
|
-
const value = args.slice(3).join(" ");
|
|
336
|
-
if (!bid || !cid || !field || !value) {
|
|
337
|
-
return error(`benchmark meta needs <bid> <cid> <field> <value> (fields: capability, distinguisher, shortcuts).\n${BENCHMARK_USAGE}`);
|
|
338
|
-
}
|
|
339
|
-
const meta = loadCaseMeta(baseDir, bid, cid);
|
|
340
|
-
if (!meta) {
|
|
341
|
-
return error(`case ${cid} not found in ${bid}`);
|
|
342
|
-
}
|
|
343
|
-
if (meta.status === "frozen") {
|
|
344
|
-
return error(`case ${cid} is frozen and cannot be modified`);
|
|
345
|
-
}
|
|
346
|
-
if (field !== "capability" && field !== "distinguisher" && field !== "shortcuts") {
|
|
347
|
-
return error(`unknown meta field "${field}" — valid fields: capability, distinguisher, shortcuts`);
|
|
348
|
-
}
|
|
349
|
-
meta[field] = value;
|
|
350
|
-
saveCaseMeta(baseDir, bid, cid, meta);
|
|
351
|
-
return success(`case ${cid} ${field} updated`);
|
|
352
|
-
}
|
|
353
|
-
default:
|
|
354
|
-
return error(`unknown benchmark subcommand: ${sub}\n${BENCHMARK_USAGE}`);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
//# sourceMappingURL=benchmark-command.js.map
|
package/lib/benchmark.d.ts
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import type { EvolutionEngine } from "./service.js";
|
|
2
|
-
export interface BenchmarkCase {
|
|
3
|
-
id: string;
|
|
4
|
-
title: string;
|
|
5
|
-
statement: string;
|
|
6
|
-
rubric: string;
|
|
7
|
-
/**
|
|
8
|
-
* Case lifecycle state (gap A5): draft → calibrating → frozen.
|
|
9
|
-
* - draft: newly added, not yet quality-checked or calibrated
|
|
10
|
-
* - calibrating: pilot run in progress (case may be edited)
|
|
11
|
-
* - frozen: calibrated, locked as a formal baseline (immutable)
|
|
12
|
-
*/
|
|
13
|
-
status?: "draft" | "calibrating" | "frozen";
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Persistent per-case metadata (stored in `cases/<cid>/meta.json`).
|
|
17
|
-
* Carries quality-gate annotations and calibration history.
|
|
18
|
-
*/
|
|
19
|
-
export interface CaseMeta {
|
|
20
|
-
status: "draft" | "calibrating" | "frozen";
|
|
21
|
-
/** What this case tests — the capability contract. */
|
|
22
|
-
capability: string;
|
|
23
|
-
/** What distinguishes a pass from a fail. */
|
|
24
|
-
distinguisher: string;
|
|
25
|
-
/** Known shortcuts the agent might use to game the rubric. */
|
|
26
|
-
shortcuts: string;
|
|
27
|
-
/** Calibration run history (appended on each pilot run). */
|
|
28
|
-
calibrationHistory: CalibrationRecord[];
|
|
29
|
-
}
|
|
30
|
-
/** One pilot-run record in the calibration history. */
|
|
31
|
-
export interface CalibrationRecord {
|
|
32
|
-
runAt: string;
|
|
33
|
-
score: number;
|
|
34
|
-
passed: boolean;
|
|
35
|
-
notes: string;
|
|
36
|
-
/** Whether the case was modified after this run. */
|
|
37
|
-
modified: boolean;
|
|
38
|
-
}
|
|
39
|
-
export interface BenchmarkDefinition {
|
|
40
|
-
id: string;
|
|
41
|
-
title: string;
|
|
42
|
-
description: string;
|
|
43
|
-
runs: number;
|
|
44
|
-
passThreshold: number;
|
|
45
|
-
createdAt: string;
|
|
46
|
-
}
|
|
47
|
-
export interface CellScore {
|
|
48
|
-
caseId: string;
|
|
49
|
-
run: number;
|
|
50
|
-
/**
|
|
51
|
-
* Failure-cell protocol (gap A2): "ok" = a real score; "failed" = the
|
|
52
|
-
* unit could not produce one (rubric decrypt error, child crash, protocol
|
|
53
|
-
* error). A failed cell is NOT a zero — aggregation excludes it and
|
|
54
|
-
* counts it, and the acceptance rule rejects a round with more failures
|
|
55
|
-
* than the threshold instead of silently averaging a 0 into the mean.
|
|
56
|
-
*/
|
|
57
|
-
status: "ok" | "failed";
|
|
58
|
-
score: number;
|
|
59
|
-
passed: boolean;
|
|
60
|
-
notes: string;
|
|
61
|
-
/**
|
|
62
|
-
* Trace evidence pointer (gap A4): the executor child's session id whose
|
|
63
|
-
* transcript produced this cell's evidence — the score can be drilled
|
|
64
|
-
* back to the exact session steps that earned it.
|
|
65
|
-
*/
|
|
66
|
-
sessionId?: string;
|
|
67
|
-
/**
|
|
68
|
-
* Runtime evidence verification (gap A3): the actual provider and model
|
|
69
|
-
* used by the evaluation units — written from the host (not the model),
|
|
70
|
-
* so it reflects reality. Combined with `caseHash`, these make material
|
|
71
|
-
* and route drift between reference and candidate runs detectable:
|
|
72
|
-
* `score.flagMaterialDrift` re-marks a candidate cell failed when its
|
|
73
|
-
* case hash no longer matches the reference (version_changed semantics).
|
|
74
|
-
*/
|
|
75
|
-
provider?: string;
|
|
76
|
-
model?: string;
|
|
77
|
-
/**
|
|
78
|
-
* Material hash: SHA-256 prefix of the case statement + rubric envelope,
|
|
79
|
-
* so a material change between reference and candidate runs is detectable.
|
|
80
|
-
* absence means pre-A3 cell (backward compatible).
|
|
81
|
-
*/
|
|
82
|
-
caseHash?: string;
|
|
83
|
-
/**
|
|
84
|
-
* Gap C3: wall-clock duration of this cell's evaluation (both executor +
|
|
85
|
-
* reviewer subagents) in milliseconds. Absent means pre-C3 cell.
|
|
86
|
-
*/
|
|
87
|
-
durationMs?: number;
|
|
88
|
-
}
|
|
89
|
-
export interface EvaluationEntry {
|
|
90
|
-
label: string;
|
|
91
|
-
refinementId?: string;
|
|
92
|
-
createdAt: string;
|
|
93
|
-
cells: CellScore[];
|
|
94
|
-
/** Code-owned aggregates (model never writes these). */
|
|
95
|
-
aggregate: Record<string, number | null>;
|
|
96
|
-
overall: number | null;
|
|
97
|
-
}
|
|
98
|
-
export interface Scoreboard {
|
|
99
|
-
reference?: EvaluationEntry;
|
|
100
|
-
candidates: EvaluationEntry[];
|
|
101
|
-
decisions: {
|
|
102
|
-
candidateLabel: string;
|
|
103
|
-
refinementId?: string;
|
|
104
|
-
accepted: boolean;
|
|
105
|
-
reasons: string[];
|
|
106
|
-
createdAt: string;
|
|
107
|
-
}[];
|
|
108
|
-
}
|
|
109
|
-
export interface AutoRollbackOutcome {
|
|
110
|
-
rolledBack: boolean;
|
|
111
|
-
message: string;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Close the acceptance loop: when the code-owned decision rejects a
|
|
115
|
-
* candidate refinement, revert it deterministically. The rollback is the
|
|
116
|
-
* same engine path as `/evolve rollback` (inverse edits rebuilt from the
|
|
117
|
-
* applied result — no LLM re-guessing), so it snapshots, versions, and
|
|
118
|
-
* audits like any other mutation. Failures (e.g. the refinement belongs to
|
|
119
|
-
* another session's history) are reported, never thrown: the command shows
|
|
120
|
-
* the manual fallback instead.
|
|
121
|
-
*/
|
|
122
|
-
export declare function rollbackRejectedCandidate(engine: EvolutionEngine, sessionId: string | undefined, candidateId: string): AutoRollbackOutcome;
|
|
123
|
-
export declare function benchmarkDir(baseDir: string, bid: string): string;
|
|
124
|
-
export declare function sanitizeId(raw: string): string;
|
|
125
|
-
export declare function createBenchmark(baseDir: string, opts: {
|
|
126
|
-
title: string;
|
|
127
|
-
description?: string;
|
|
128
|
-
runs?: number;
|
|
129
|
-
passThreshold?: number;
|
|
130
|
-
}): BenchmarkDefinition;
|
|
131
|
-
export declare function listBenchmarks(baseDir: string): BenchmarkDefinition[];
|
|
132
|
-
export declare function loadBenchmark(baseDir: string, bid: string): BenchmarkDefinition | undefined;
|
|
133
|
-
export declare function addCase(baseDir: string, bid: string, title: string, statement: string, rubric: string, rubricKey?: Buffer): BenchmarkCase;
|
|
134
|
-
export declare function listCases(baseDir: string, bid: string): BenchmarkCase[];
|
|
135
|
-
export declare function loadScoreboard(baseDir: string, bid: string): Scoreboard;
|
|
136
|
-
export declare function saveScoreboard(baseDir: string, bid: string, board: Scoreboard): void;
|
|
137
|
-
export declare function loadCaseMeta(baseDir: string, bid: string, cid: string): CaseMeta | undefined;
|
|
138
|
-
export declare function saveCaseMeta(baseDir: string, bid: string, cid: string, meta: CaseMeta): void;
|
|
139
|
-
/**
|
|
140
|
-
* Transition a case's lifecycle state. Throws on illegal transitions.
|
|
141
|
-
* draft → calibrating (start pilot)
|
|
142
|
-
* calibrating → draft (abandon calibration)
|
|
143
|
-
* calibrating → frozen (lock baseline)
|
|
144
|
-
*/
|
|
145
|
-
export declare function transitionCaseStatus(baseDir: string, bid: string, cid: string, to: "draft" | "calibrating" | "frozen"): CaseMeta;
|
|
146
|
-
/**
|
|
147
|
-
* Quality-check a case: mechanical validation without LLM calls.
|
|
148
|
-
* Returns human-readable problems; empty array means the case passes.
|
|
149
|
-
*/
|
|
150
|
-
export declare function caseCheckProblems(baseDir: string, bid: string, cid: string): string[];
|
|
151
|
-
//# sourceMappingURL=benchmark.d.ts.map
|