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.
Files changed (161) hide show
  1. package/README.md +42 -115
  2. package/README.zh.md +33 -93
  3. package/client/client.js +253 -0
  4. package/cordis.patch.yml +2 -2
  5. package/lib/card-routes.d.ts +32 -0
  6. package/lib/card-routes.js +92 -0
  7. package/lib/index.d.ts +65 -217
  8. package/lib/index.js +74 -234
  9. package/lib/known-workspaces.d.ts +22 -0
  10. package/lib/known-workspaces.js +42 -0
  11. package/lib/memory-guide.d.ts +13 -14
  12. package/lib/memory-guide.js +34 -21
  13. package/lib/memory-section.d.ts +77 -0
  14. package/lib/memory-section.js +189 -0
  15. package/lib/memory-snapshot.d.ts +54 -0
  16. package/lib/memory-snapshot.js +125 -0
  17. package/package.json +8 -17
  18. package/lib/apply.d.ts +0 -22
  19. package/lib/apply.js +0 -157
  20. package/lib/approval.d.ts +0 -73
  21. package/lib/approval.js +0 -127
  22. package/lib/audit-log.d.ts +0 -19
  23. package/lib/audit-log.js +0 -52
  24. package/lib/auto.d.ts +0 -236
  25. package/lib/auto.js +0 -773
  26. package/lib/autocase.d.ts +0 -38
  27. package/lib/autocase.js +0 -76
  28. package/lib/benchmark-command.d.ts +0 -9
  29. package/lib/benchmark-command.js +0 -357
  30. package/lib/benchmark.d.ts +0 -151
  31. package/lib/benchmark.js +0 -250
  32. package/lib/command-util.d.ts +0 -70
  33. package/lib/command-util.js +0 -123
  34. package/lib/command.d.ts +0 -13
  35. package/lib/command.js +0 -134
  36. package/lib/consolidate.d.ts +0 -90
  37. package/lib/consolidate.js +0 -180
  38. package/lib/copy.d.ts +0 -37
  39. package/lib/copy.js +0 -58
  40. package/lib/declines.d.ts +0 -103
  41. package/lib/declines.js +0 -179
  42. package/lib/evaluate.d.ts +0 -74
  43. package/lib/evaluate.js +0 -271
  44. package/lib/evolve-event.d.ts +0 -40
  45. package/lib/evolve-event.js +0 -60
  46. package/lib/extraction-phase.d.ts +0 -132
  47. package/lib/extraction-phase.js +0 -236
  48. package/lib/failures.d.ts +0 -42
  49. package/lib/failures.js +0 -171
  50. package/lib/fate.d.ts +0 -130
  51. package/lib/fate.js +0 -350
  52. package/lib/goal-command.d.ts +0 -7
  53. package/lib/goal-command.js +0 -37
  54. package/lib/goal.d.ts +0 -72
  55. package/lib/goal.js +0 -72
  56. package/lib/inject.d.ts +0 -90
  57. package/lib/inject.js +0 -164
  58. package/lib/injection-caps.d.ts +0 -4
  59. package/lib/injection-caps.js +0 -4
  60. package/lib/injection-directory.d.ts +0 -29
  61. package/lib/injection-directory.js +0 -78
  62. package/lib/injection-rank.d.ts +0 -85
  63. package/lib/injection-rank.js +0 -161
  64. package/lib/listener.d.ts +0 -45
  65. package/lib/listener.js +0 -199
  66. package/lib/llm-text.d.ts +0 -104
  67. package/lib/llm-text.js +0 -140
  68. package/lib/logfile.d.ts +0 -71
  69. package/lib/logfile.js +0 -159
  70. package/lib/maintenance-commands.d.ts +0 -23
  71. package/lib/maintenance-commands.js +0 -136
  72. package/lib/memory-agent.d.ts +0 -93
  73. package/lib/memory-agent.js +0 -300
  74. package/lib/memory-apply.d.ts +0 -44
  75. package/lib/memory-apply.js +0 -202
  76. package/lib/memory-benchmark.d.ts +0 -76
  77. package/lib/memory-benchmark.js +0 -170
  78. package/lib/memory-index.d.ts +0 -114
  79. package/lib/memory-index.js +0 -197
  80. package/lib/memory-manifest.d.ts +0 -16
  81. package/lib/memory-manifest.js +0 -70
  82. package/lib/message-source.d.ts +0 -23
  83. package/lib/message-source.js +0 -12
  84. package/lib/mount-command.d.ts +0 -10
  85. package/lib/mount-command.js +0 -48
  86. package/lib/mount.d.ts +0 -42
  87. package/lib/mount.js +0 -212
  88. package/lib/notify.d.ts +0 -48
  89. package/lib/notify.js +0 -57
  90. package/lib/plan-command.d.ts +0 -12
  91. package/lib/plan-command.js +0 -38
  92. package/lib/plan.d.ts +0 -16
  93. package/lib/plan.js +0 -126
  94. package/lib/planner.d.ts +0 -61
  95. package/lib/planner.js +0 -144
  96. package/lib/pool.d.ts +0 -7
  97. package/lib/pool.js +0 -25
  98. package/lib/prefix-cache.d.ts +0 -79
  99. package/lib/prefix-cache.js +0 -168
  100. package/lib/project.d.ts +0 -28
  101. package/lib/project.js +0 -66
  102. package/lib/projection.d.ts +0 -22
  103. package/lib/projection.js +0 -112
  104. package/lib/promotion.d.ts +0 -94
  105. package/lib/promotion.js +0 -171
  106. package/lib/recall.d.ts +0 -85
  107. package/lib/recall.js +0 -142
  108. package/lib/record-language.d.ts +0 -85
  109. package/lib/record-language.js +0 -152
  110. package/lib/render.d.ts +0 -13
  111. package/lib/render.js +0 -80
  112. package/lib/review-scheduler.d.ts +0 -38
  113. package/lib/review-scheduler.js +0 -183
  114. package/lib/review.d.ts +0 -60
  115. package/lib/review.js +0 -145
  116. package/lib/rollback.d.ts +0 -9
  117. package/lib/rollback.js +0 -68
  118. package/lib/rubric.d.ts +0 -29
  119. package/lib/rubric.js +0 -119
  120. package/lib/runtime-commands.d.ts +0 -14
  121. package/lib/runtime-commands.js +0 -115
  122. package/lib/runtime.d.ts +0 -24
  123. package/lib/runtime.js +0 -87
  124. package/lib/score.d.ts +0 -64
  125. package/lib/score.js +0 -191
  126. package/lib/search.d.ts +0 -83
  127. package/lib/search.js +0 -136
  128. package/lib/service.d.ts +0 -63
  129. package/lib/service.js +0 -253
  130. package/lib/skill-render.d.ts +0 -23
  131. package/lib/skill-render.js +0 -69
  132. package/lib/skill.d.ts +0 -15
  133. package/lib/skill.js +0 -80
  134. package/lib/skillquality.d.ts +0 -85
  135. package/lib/skillquality.js +0 -320
  136. package/lib/source.d.ts +0 -30
  137. package/lib/source.js +0 -43
  138. package/lib/state.d.ts +0 -26
  139. package/lib/state.js +0 -151
  140. package/lib/store.d.ts +0 -61
  141. package/lib/store.js +0 -164
  142. package/lib/token-usage.d.ts +0 -68
  143. package/lib/token-usage.js +0 -211
  144. package/lib/tool.d.ts +0 -34
  145. package/lib/tool.js +0 -320
  146. package/lib/turn-snapshot.d.ts +0 -78
  147. package/lib/turn-snapshot.js +0 -252
  148. package/lib/types.d.ts +0 -218
  149. package/lib/types.js +0 -133
  150. package/lib/usage.d.ts +0 -36
  151. package/lib/usage.js +0 -98
  152. package/lib/validate.d.ts +0 -28
  153. package/lib/validate.js +0 -181
  154. package/lib/wrapup-candidates.d.ts +0 -127
  155. package/lib/wrapup-candidates.js +0 -161
  156. package/lib/wrapup-command.d.ts +0 -10
  157. package/lib/wrapup-command.js +0 -243
  158. package/lib/wrapup-proposals.d.ts +0 -101
  159. package/lib/wrapup-proposals.js +0 -281
  160. package/lib/wrapup.d.ts +0 -56
  161. 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
@@ -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
@@ -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