@dailephd/my-dev-kit-lab 0.9.0 → 0.9.2

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 (48) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +10 -3
  3. package/dist/src/agents/adapters/claudeAdapter.js +6 -3
  4. package/dist/src/agents/adapters/codexAdapter.js +51 -10
  5. package/dist/src/agents/index.js +1 -0
  6. package/dist/src/agents/normalizeAgentTelemetry.js +50 -0
  7. package/dist/src/agents/parseAgentTokenUsage.js +71 -49
  8. package/dist/src/agents/providerBuildObservation.js +97 -0
  9. package/dist/src/audits/core/projectInventory.js +1 -0
  10. package/dist/src/cli/help.js +8 -2
  11. package/dist/src/commands/runExperimentDescribeCommand.js +31 -0
  12. package/dist/src/commands/runExperimentRunCommand.js +193 -5
  13. package/dist/src/core/runMeasuredCommand.js +4 -0
  14. package/dist/src/evaluation/benchmarkSandbox/gitExecutor.js +3 -1
  15. package/dist/src/experiments/plugins/agentSuccessRate/campaignCheckpoint.js +216 -0
  16. package/dist/src/experiments/plugins/agentSuccessRate/campaignCheckpointStore.js +588 -0
  17. package/dist/src/experiments/plugins/agentSuccessRate/campaignEvidenceQuality.js +77 -0
  18. package/dist/src/experiments/plugins/agentSuccessRate/campaignExecution.js +314 -0
  19. package/dist/src/experiments/plugins/agentSuccessRate/campaignIdentity.js +111 -0
  20. package/dist/src/experiments/plugins/agentSuccessRate/campaignProgress.js +175 -0
  21. package/dist/src/experiments/plugins/agentSuccessRate/campaignQueue.js +11 -0
  22. package/dist/src/experiments/plugins/agentSuccessRate/campaignRecovery.js +256 -0
  23. package/dist/src/experiments/plugins/agentSuccessRate/campaignResumableExecution.js +207 -0
  24. package/dist/src/experiments/plugins/agentSuccessRate/index.js +6 -0
  25. package/dist/src/experiments/plugins/agentSuccessRate/plugin.js +32 -22
  26. package/dist/src/experiments/plugins/agentSuccessRate/realAgentExecution.js +29 -7
  27. package/dist/src/experiments/plugins/agentSuccessRate/timeoutPresets.js +9 -0
  28. package/dist/src/report/experiments/agentSuccessCampaignProgressReportModel.js +1 -0
  29. package/dist/src/report/experiments/buildAgentSuccessCampaignProgressReport.js +6 -0
  30. package/dist/src/report/experiments/buildAgentSuccessRateReport.js +11 -0
  31. package/dist/src/report/experiments/buildPluginExperimentReport.js +1 -1
  32. package/dist/src/report/experiments/renderAgentSuccessCampaignProgressHtml.js +6 -0
  33. package/dist/src/report/experiments/renderAgentSuccessCampaignProgressText.js +25 -0
  34. package/dist/src/report/experiments/renderAgentSuccessRateHtml.js +3 -1
  35. package/dist/src/report/experiments/renderAgentSuccessRateText.js +7 -0
  36. package/dist/src/report/experiments/writeAgentSuccessCampaignProgressReport.js +139 -0
  37. package/dist/src/report/experiments/writePluginExperimentReports.js +4 -3
  38. package/dist/src/securityValidation/attackScenarios/payloadCorpus.js +0 -0
  39. package/dist/src/securityValidation/packageChecks/parseNpmPackDryRun.js +34 -4
  40. package/dist/src/securityValidation/packageChecks/requiredPackageContents.js +106 -2
  41. package/dist/src/securityValidation/packageChecks/runPackageChecks.js +31 -16
  42. package/dist/src/securityValidation/staticScans/semgrep.js +68 -64
  43. package/dist/src/securityValidation/types.js +0 -4
  44. package/dist/src/securityValidation/validate/runSecurityValidation.js +1 -1
  45. package/docs/METRICS.md +9 -0
  46. package/examples/tutorial-browser/prepare.mjs +13 -13
  47. package/examples/tutorial-browser/server.mjs +13 -13
  48. package/package.json +1 -1
@@ -0,0 +1,314 @@
1
+ import { lstat, mkdtemp, readFile, realpath, rm, rmdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ import { fileURLToPath } from "node:url";
5
+ import { runAgentPrompt } from "../../../agents/index.js";
6
+ import { trustedProviderObservation } from "../../../agents/providerBuildObservation.js";
7
+ import { resolveWithinRoot } from "../../../core/pathSafety.js";
8
+ import { scanProjectTree } from "../../../evaluation/benchmarkSandbox/treeSnapshot.js";
9
+ import { buildCampaignQueue } from "./campaignQueue.js";
10
+ import { campaignAssert, canonicalCampaignJson, compareCampaignIdentity, createCampaignIdentity } from "./campaignIdentity.js";
11
+ import { createCampaignCheckpoint, transitionCampaignCheckpoint } from "./campaignCheckpoint.js";
12
+ import { acquireCampaignDispatch, assertCampaignDispatch, persistCampaignArtifact, persistCampaignSupportingArtifacts, prepareCampaignCompletion, prepareCampaignProviderOutput, readCampaignCheckpoint, releaseCampaignDispatch, writeCampaignCheckpoint } from "./campaignCheckpointStore.js";
13
+ import { boundMessage, executeAgentSuccessTreatment, resolveControlledBenchmarkProject, resolveSandboxRuntimeRoot } from "./execution.js";
14
+ import { executeAgentSuccessRepairTreatment } from "./repairExecution.js";
15
+ import { agentSuccessAgentArtifactDirectory, createRealAgentProposalSource } from "./realAgentExecution.js";
16
+ import { projectAgentFacingTask } from "./agentTaskProjection.js";
17
+ import { AgentSuccessPackContextBuilder, buildContextTaskInput, buildRawFullFileContext } from "./contextGeneration.js";
18
+ import { analyzeAgentSuccessRate } from "./analysis.js";
19
+ import { buildAgentSuccessRateExecutionArtifact, validateAgentSuccessRateExecutionArtifact, AGENT_SUCCESS_RATE_EXECUTION_ARTIFACT_FILE } from "./executionArtifact.js";
20
+ import { buildAgentSuccessRateAnalysisArtifact, validateAgentSuccessRateAnalysisArtifact, validateAgentSuccessRateArtifactFamily, AGENT_SUCCESS_RATE_ANALYSIS_ARTIFACT_FILE } from "./analysisArtifact.js";
21
+ import { defaultContextDependencies, sealTask, writeAgentSuccessRateArtifactTargets } from "./plugin.js";
22
+ import { DEFAULT_AGENT_SUCCESS_KIT_COMMAND } from "./contextGeneration.js";
23
+ import { executeResumableCampaign } from "./campaignResumableExecution.js";
24
+ const preparations = new WeakMap();
25
+ async function establishPhysicalRoot(root) {
26
+ const lexical = path.resolve(root);
27
+ const stat = await lstat(lexical);
28
+ campaignAssert(stat.isDirectory() && !stat.isSymbolicLink(), "IDENTITY_INPUT_UNSAFE");
29
+ return { lexical, physical: await realpath(lexical) };
30
+ }
31
+ async function currentBytes(file, authorizedRoot, descendantsValidated = false) {
32
+ const lexicalRoot = authorizedRoot.lexical;
33
+ const lexicalFile = path.resolve(file);
34
+ const relative = path.relative(lexicalRoot, lexicalFile);
35
+ campaignAssert(relative !== "" && relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative), "IDENTITY_INPUT_UNSAFE");
36
+ // Canonicalizing the trusted root accepts OS aliases of that root. A file is then
37
+ // checked against the corresponding child reached from the canonical root itself.
38
+ let physicalCandidate = authorizedRoot.physical;
39
+ if (!descendantsValidated) {
40
+ for (const part of relative.split(path.sep)) {
41
+ physicalCandidate = path.join(physicalCandidate, part);
42
+ const componentStat = await lstat(physicalCandidate);
43
+ campaignAssert(!componentStat.isSymbolicLink(), "IDENTITY_INPUT_UNSAFE");
44
+ }
45
+ }
46
+ else {
47
+ physicalCandidate = path.join(physicalCandidate, relative);
48
+ }
49
+ const authorizedFileStat = await lstat(physicalCandidate);
50
+ campaignAssert(authorizedFileStat.isFile() && !authorizedFileStat.isSymbolicLink() && authorizedFileStat.size <= 32 * 1024 * 1024, "IDENTITY_INPUT_UNSAFE");
51
+ const stat = await lstat(lexicalFile);
52
+ campaignAssert(stat.isFile() && !stat.isSymbolicLink() && stat.size <= 32 * 1024 * 1024, "IDENTITY_INPUT_UNSAFE");
53
+ campaignAssert(authorizedFileStat?.isFile() && authorizedFileStat.dev === stat.dev && authorizedFileStat.ino === stat.ino, "IDENTITY_INPUT_UNSAFE");
54
+ const bytes = await readFile(lexicalFile);
55
+ const after = await lstat(lexicalFile);
56
+ const authorizedAfter = await lstat(physicalCandidate);
57
+ campaignAssert(bytes.length === stat.size && after.isFile() && !after.isSymbolicLink() && after.size === stat.size && after.dev === stat.dev && after.ino === stat.ino && after.mtimeMs === stat.mtimeMs && authorizedAfter.dev === authorizedFileStat.dev && authorizedAfter.ino === authorizedFileStat.ino && authorizedAfter.size === authorizedFileStat.size && authorizedAfter.mtimeMs === authorizedFileStat.mtimeMs, "IDENTITY_INPUT_CHANGED");
58
+ return bytes;
59
+ }
60
+ async function produceIdentity(input) {
61
+ buildCampaignQueue(input.tasks, input.treatments, "all-selected-cases");
62
+ const sourceRoot = input.sourceRoot ?? fileURLToPath(new URL("../../../../", import.meta.url));
63
+ const physicalSourceRoot = await establishPhysicalRoot(sourceRoot);
64
+ const sourceDirectory = path.join(sourceRoot, "src");
65
+ const sourceDirectoryStat = await lstat(sourceDirectory);
66
+ campaignAssert(sourceDirectoryStat.isDirectory() && !sourceDirectoryStat.isSymbolicLink(), "IDENTITY_INPUT_UNSAFE");
67
+ const sources = await scanProjectTree(sourceDirectory, [".git", "node_modules"]);
68
+ const physicalCorpusRoot = input.corpusFile === null ? null : await establishPhysicalRoot(input.corpusRoot);
69
+ campaignAssert(sources.length <= 9998, "DATA_BOUND");
70
+ const sourceFiles = [];
71
+ for (const file of [...sources.map((p) => `src/${p}`), "package.json", "package-lock.json"])
72
+ sourceFiles.push({ path: file, bytes: await currentBytes(resolveWithinRoot(sourceRoot, file), physicalSourceRoot, true) });
73
+ const projects = [];
74
+ for (const projectId of new Set(input.tasks.map((t) => t.benchmarkProject))) {
75
+ const root = await resolveControlledBenchmarkProject(input.boundary.toolRoot, projectId);
76
+ const physicalProjectRoot = await establishPhysicalRoot(root);
77
+ const paths = await scanProjectTree(root, [".git"]);
78
+ const files = [];
79
+ for (const file of paths)
80
+ files.push({ path: file, bytes: await currentBytes(resolveWithinRoot(root, file), physicalProjectRoot, true) });
81
+ projects.push({ projectId, files });
82
+ }
83
+ const provider = input.provider;
84
+ const allowed = provider.kind === "deterministic-fixture" ? ["kind"] : provider.kind === "trusted-simulated-provider" ? ["kind", "simulationId", "providerId", "timeoutMs", "repairAttempts", "runAgent", "contextDependencies"] : ["kind", "providerId", "timeoutMs", "repairAttempts", "includeRealAgents", "trustedExecutable", "kitCommand", "contextDependencies", "env"];
85
+ campaignAssert(Object.keys(provider).every(key => allowed.includes(key)), "INCONSISTENT_EXECUTION_MODE");
86
+ const simulated = provider.kind === "trusted-simulated-provider";
87
+ campaignAssert(["deterministic-fixture", "trusted-simulated-provider", "real-agent"].includes(provider.kind), "INVALID_EXECUTION_MODE");
88
+ if (simulated)
89
+ campaignAssert(provider.runAgent !== runAgentPrompt && /^[A-Za-z0-9._-]+$/.test(provider.simulationId), "SIMULATION_CONTRACT_INVALID");
90
+ const real = provider.kind === "real-agent";
91
+ if (real)
92
+ campaignAssert(provider.includeRealAgents === undefined || provider.includeRealAgents === true, "REAL_PROVIDER_AUTHORIZATION_REQUIRED");
93
+ const observed = real && provider.includeRealAgents === true && provider.trustedExecutable ? await trustedProviderObservation(provider.trustedExecutable, provider.providerId) : null;
94
+ let retrievalVersion = null;
95
+ if (real && observed !== null) {
96
+ const commandsDir = await mkdtemp(path.join(os.tmpdir(), "lab-campaign-kit-proof-"));
97
+ try {
98
+ retrievalVersion = (await (provider.contextDependencies ?? defaultContextDependencies()).probeVersion({ kitCommand: provider.kitCommand ?? DEFAULT_AGENT_SUCCESS_KIT_COMMAND, commandsDir })).version ?? null;
99
+ campaignAssert(typeof retrievalVersion === "string" && retrievalVersion.length > 0 && retrievalVersion.length <= 256, "RETRIEVAL_IDENTITY_UNVERIFIABLE");
100
+ }
101
+ finally {
102
+ await rm(commandsDir, { recursive: true, force: true });
103
+ }
104
+ }
105
+ const functions = (object) => Object.entries(object).map(([key, value]) => ({ key, source: String(value) })).sort((a, b) => a.key < b.key ? -1 : 1);
106
+ return createCampaignIdentity({
107
+ tasks: input.tasks,
108
+ corpusBytes: input.corpusFile === null ? null : await currentBytes(input.corpusFile, physicalCorpusRoot), projects, sourceFiles,
109
+ config: provider.kind === "deterministic-fixture" ? { providerId: provider.kind, timeoutMs: 1000, repairAttempts: 0 } : { providerId: provider.providerId, timeoutMs: provider.timeoutMs, repairAttempts: provider.repairAttempts },
110
+ contextConfiguration: { contract: "existing-agent-success-context-v1", treatments: [...input.treatments] },
111
+ retrievalConfiguration: { contract: simulated ? "trusted-simulated-retrieval-v1" : real ? "real-provider-retrieval-v1" : "no-retrieval-fixture-v1", dependencies: simulated ? functions(provider.contextDependencies) : real ? functions(provider.contextDependencies ?? defaultContextDependencies()) : [], ...(real ? { kitCommand: provider.kitCommand ?? DEFAULT_AGENT_SUCCESS_KIT_COMMAND, version: retrievalVersion } : {}), executionDependencies: functions(input.dependencies ?? {}) },
112
+ verifiedProviderObservation: simulated ? Buffer.from(canonicalCampaignJson({ contract: "trusted-simulated-provider-v1", simulationId: provider.simulationId, implementation: String(provider.runAgent) })) : observed
113
+ });
114
+ }
115
+ /** Reads trusted current-byte inputs itself. The capability cannot be constructed from a claimed verified identity. */
116
+ export async function prepareAgentSuccessCampaign(input) {
117
+ const snapshot = { ...input, boundary: { ...input.boundary }, tasks: structuredClone(input.tasks), treatments: [...input.treatments], provider: { ...input.provider }, dependencies: input.dependencies ? { ...input.dependencies } : undefined };
118
+ const identity = await produceIdentity(snapshot);
119
+ const prepared = Object.freeze({ identity: structuredClone(identity) });
120
+ preparations.set(prepared, snapshot);
121
+ return prepared;
122
+ }
123
+ /** Internal v2 gate: retained producer capability and newly observed current bytes are both required. */
124
+ export async function validatePreparedCampaign(prepared) {
125
+ const input = preparations.get(prepared);
126
+ campaignAssert(input, "IDENTITY_PRODUCER_REQUIRED");
127
+ const identity = await produceIdentity(input);
128
+ campaignAssert(compareCampaignIdentity(identity, prepared.identity) === "MATCH", "IDENTITY_PROOF_MISSING_OR_CHANGED");
129
+ return { input: { ...input, boundary: { ...input.boundary }, tasks: structuredClone(input.tasks), treatments: [...input.treatments], provider: { ...input.provider }, dependencies: input.dependencies ? { ...input.dependencies } : undefined }, identity };
130
+ }
131
+ /** Explicit resumable internal API; the Prompt4 entrypoint and its default behavior stay intact. */
132
+ export async function executeAgentSuccessCampaignV2(prepared, args) {
133
+ return executeResumableCampaign(prepared, args);
134
+ }
135
+ /** Internal entrypoint only. New campaign dispatch; reopening any existing generation belongs to Prompt 5. */
136
+ export async function executeAgentSuccessCampaign(prepared, args) {
137
+ const outcome = { status: "failed", checkpoint: null, treatmentEvidence: [], completedCaseIds: [], errors: [], scientificArtifactsWritten: false };
138
+ const input = preparations.get(prepared);
139
+ if (!input) {
140
+ outcome.errors.push("IDENTITY_PRODUCER_REQUIRED");
141
+ return outcome;
142
+ }
143
+ let identity;
144
+ try {
145
+ identity = await produceIdentity(input);
146
+ }
147
+ catch {
148
+ outcome.errors.push("IDENTITY_INPUT_UNAVAILABLE");
149
+ return outcome;
150
+ }
151
+ if (compareCampaignIdentity(identity, prepared.identity) !== "MATCH") {
152
+ outcome.errors.push("IDENTITY_PROOF_MISSING_OR_CHANGED");
153
+ return outcome;
154
+ }
155
+ // Preserve historical proof diagnostics, then block live mode before any v1 state or dispatch.
156
+ if (input.provider.kind === "real-agent") {
157
+ outcome.errors.push("REAL_PROVIDER_REQUIRES_V2");
158
+ return outcome;
159
+ }
160
+ const { boundary, tasks, provider } = input;
161
+ const queue = buildCampaignQueue(tasks, input.treatments, args.limit);
162
+ let ownership;
163
+ let packBuilder;
164
+ let ownedRuntimeRoot;
165
+ const patchFiles = [], contextFiles = [], cases = [];
166
+ const at = () => new Date().toISOString();
167
+ const publish = async (checkpoint) => {
168
+ await writeCampaignCheckpoint(boundary, checkpoint, tasks, (phase) => args.hooks?.publication?.(checkpoint.generation, phase), ownership);
169
+ outcome.checkpoint = checkpoint;
170
+ };
171
+ try {
172
+ ownership = await acquireCampaignDispatch(boundary, identity);
173
+ const existing = await readCampaignCheckpoint(boundary, identity, tasks);
174
+ if (existing.checkpoint || existing.temporaryFiles.length) {
175
+ outcome.checkpoint = existing.checkpoint;
176
+ outcome.status = "resume-not-yet-supported";
177
+ return outcome;
178
+ }
179
+ await publish(createCampaignCheckpoint(identity, tasks, at()));
180
+ const runtimeRoot = await resolveSandboxRuntimeRoot(boundary.outputRoot, boundary.toolRoot);
181
+ try {
182
+ await lstat(runtimeRoot);
183
+ }
184
+ catch (error) {
185
+ if (error.code !== "ENOENT")
186
+ throw error;
187
+ ownedRuntimeRoot = runtimeRoot;
188
+ }
189
+ if (provider.kind === "trusted-simulated-provider")
190
+ packBuilder = new AgentSuccessPackContextBuilder("trusted-simulated-kit", provider.contextDependencies);
191
+ for (let i = 0; i < queue.length; i += 2) {
192
+ const task = queue[i].task;
193
+ const forbiddenByTask = new Map();
194
+ const executionTask = provider.kind === "deterministic-fixture" ? task : sealTask(task, forbiddenByTask);
195
+ const canonicalProjectRoot = await resolveControlledBenchmarkProject(boundary.toolRoot, task.benchmarkProject);
196
+ const contextInput = buildContextTaskInput(executionTask);
197
+ const contexts = packBuilder ? { "raw-full-file": await buildRawFullFileContext(contextInput, canonicalProjectRoot), "context-pack": await packBuilder.build(contextInput, canonicalProjectRoot) } : null;
198
+ const treatments = [];
199
+ for (const unit of queue.slice(i, i + 2)) {
200
+ await assertCampaignDispatch(boundary, identity, ownership);
201
+ // Reverify current-byte identity before every dispatch, including the second treatment.
202
+ campaignAssert(compareCampaignIdentity(identity, await produceIdentity(input)) === "MATCH", "IDENTITY_CHANGED_BEFORE_DISPATCH");
203
+ campaignAssert(outcome.checkpoint.units[unit.checkpointIndex].state === "pending", "UNIT_NOT_PENDING");
204
+ await publish(transitionCampaignCheckpoint(outcome.checkpoint, tasks, unit.checkpointIndex, "in-progress", at()));
205
+ const common = { task: executionTask, treatmentId: unit.treatmentId, runId: args.runId, canonicalProjectRoot, runtimeRoot, privateRoots: [boundary.outputRoot, boundary.toolRoot], dependencies: input.dependencies };
206
+ const result = provider.kind === "trusted-simulated-provider" && contexts ? await executeAgentSuccessRepairTreatment({ ...common, repair: {
207
+ providerId: provider.providerId, repairAttempts: provider.repairAttempts,
208
+ createProposalSource: ({ attemptNumber, feedback }) => createRealAgentProposalSource({
209
+ settings: { providerId: provider.providerId, timeoutMs: provider.timeoutMs, outDir: boundary.outputRoot, privateRoots: common.privateRoots, protectedRoots: [boundary.toolRoot, boundary.outputRoot, runtimeRoot, canonicalProjectRoot],
210
+ runAgent: async (request) => {
211
+ await assertCampaignDispatch(boundary, identity, ownership);
212
+ await prepareCampaignProviderOutput(boundary, identity, ownership, agentSuccessAgentArtifactDirectory(task.benchmarkProject, task.id, unit.treatmentId, attemptNumber));
213
+ return provider.runAgent(request);
214
+ } },
215
+ runId: args.runId, task: projectAgentFacingTask(executionTask), contexts,
216
+ forbidden: forbiddenByTask.get(task.id) ?? [], attemptNumber,
217
+ ...(feedback ? { repair: { feedback, maxAttempts: 1 + provider.repairAttempts } } : {})
218
+ })
219
+ } }) : await executeAgentSuccessTreatment(common);
220
+ outcome.treatmentEvidence.push({ caseId: task.id, evidence: result.evidence });
221
+ treatments.push(result.evidence);
222
+ const limit = result.evidence.realAgent?.providerStatus === "agent-limit-reached";
223
+ if (limit || result.evidence.status !== "completed" || result.evidence.availability !== "complete") {
224
+ await publish(transitionCampaignCheckpoint(outcome.checkpoint, tasks, unit.checkpointIndex, limit ? "paused-limit" : "incomplete", at(), null, limit ? "agent-limit-reached" : null));
225
+ outcome.status = limit ? "provider-limit" : "incomplete";
226
+ return outcome;
227
+ }
228
+ await persistCampaignSupportingArtifacts(boundary, identity, ownership, task, result);
229
+ const completion = await prepareCampaignCompletion(boundary, identity, task, result.evidence);
230
+ await publish(transitionCampaignCheckpoint(outcome.checkpoint, tasks, unit.checkpointIndex, "completed", at(), completion));
231
+ patchFiles.push(...result.patchFiles);
232
+ contextFiles.push(...result.contextFiles);
233
+ }
234
+ outcome.completedCaseIds.push(task.id);
235
+ cases.push({ caseId: task.id, caseName: task.title, benchmarkProject: task.benchmarkProject, taskLocality: task.taskLocality, fixtureId: provider.kind === "deterministic-fixture" ? task.deterministicFixture.id : "", treatments });
236
+ }
237
+ const complete = outcome.checkpoint.units.every((u) => u.state === "completed");
238
+ outcome.status = complete ? "completed" : "partial";
239
+ if (complete) {
240
+ const executionMode = provider.kind === "deterministic-fixture" ? "deterministic-fixture" : "real-agent";
241
+ const analysis = analyzeAgentSuccessRate(tasks, cases, executionMode);
242
+ const common = { runId: args.runId, pluginId: "agent-success-rate", pluginSchemaVersion: "1.0.0", startedAt: outcome.checkpoint.createdAt, completedAt: at() };
243
+ const execution = buildAgentSuccessRateExecutionArtifact({ ...common, cases, ...(provider.kind === "deterministic-fixture" ? {} : { realAgent: { providerId: provider.providerId, timeoutMs: provider.timeoutMs, repairAttempts: provider.repairAttempts, attemptsPerTreatment: (1 + provider.repairAttempts), promptTransport: "stdin", contextEffectEvaluated: analysis.contextEffectEvaluated } }) });
244
+ const scientific = buildAgentSuccessRateAnalysisArtifact({ ...common, analysis });
245
+ campaignAssert([...validateAgentSuccessRateExecutionArtifact(execution), ...validateAgentSuccessRateAnalysisArtifact(scientific), ...validateAgentSuccessRateArtifactFamily(execution, scientific)].length === 0, "SCIENTIFIC_ARTIFACT_INVALID");
246
+ const targets = [...contextFiles, ...patchFiles].map((f) => ({ filePath: resolveWithinRoot(boundary.outputRoot, f.relativePath), content: f.content }));
247
+ targets.push({ filePath: resolveWithinRoot(boundary.outputRoot, AGENT_SUCCESS_RATE_EXECUTION_ARTIFACT_FILE), content: `${JSON.stringify(execution, null, 2)}\n` }, { filePath: resolveWithinRoot(boundary.outputRoot, AGENT_SUCCESS_RATE_ANALYSIS_ARTIFACT_FILE), content: `${JSON.stringify(scientific, null, 2)}\n` });
248
+ await writeAgentSuccessRateArtifactTargets(targets, {
249
+ ensureDirectory: async () => { },
250
+ exists: async (file) => { try {
251
+ await lstat(file);
252
+ return true;
253
+ }
254
+ catch (error) {
255
+ if (error.code === "ENOENT")
256
+ return false;
257
+ throw error;
258
+ } },
259
+ writeFile: (file, content) => persistCampaignArtifact(boundary, identity, ownership, path.relative(boundary.outputRoot, file).replace(/\\/g, "/"), content),
260
+ // Durable campaign evidence is never rolled back by final scientific publication.
261
+ removeFile: async () => { }
262
+ }, async (target) => {
263
+ await persistCampaignArtifact(boundary, identity, ownership, path.relative(boundary.outputRoot, target.filePath).replace(/\\/g, "/"), target.content, outcome.checkpoint);
264
+ return true;
265
+ });
266
+ outcome.scientificArtifactsWritten = true;
267
+ }
268
+ }
269
+ catch (error) {
270
+ outcome.status = "failed";
271
+ outcome.errors.push(boundMessage(error instanceof Error ? error.message : "CAMPAIGN_FAILED", [boundary.outputRoot, boundary.toolRoot, input.sourceRoot ?? ""]));
272
+ // Publication can fail after committing. Read the durable truth; never dispatch again in this invocation.
273
+ if (ownership)
274
+ try {
275
+ outcome.checkpoint = (await readCampaignCheckpoint(boundary, identity, tasks)).checkpoint;
276
+ }
277
+ catch {
278
+ outcome.errors.push("CHECKPOINT_READ_FAILED");
279
+ }
280
+ }
281
+ finally {
282
+ if (packBuilder)
283
+ try {
284
+ const reason = await packBuilder.dispose();
285
+ if (reason) {
286
+ outcome.errors.push("CONTEXT_CLEANUP_FAILED");
287
+ outcome.status = "failed";
288
+ }
289
+ }
290
+ catch {
291
+ outcome.errors.push("CONTEXT_CLEANUP_FAILED");
292
+ outcome.status = "failed";
293
+ }
294
+ if (ownedRuntimeRoot)
295
+ try {
296
+ await rmdir(ownedRuntimeRoot);
297
+ }
298
+ catch (error) {
299
+ if (error.code !== "ENOENT") {
300
+ outcome.errors.push("RUNTIME_ROOT_NOT_REMOVED");
301
+ outcome.status = "failed";
302
+ }
303
+ }
304
+ if (ownership)
305
+ try {
306
+ await releaseCampaignDispatch(boundary, identity, ownership);
307
+ }
308
+ catch {
309
+ outcome.errors.push("DISPATCH_RELEASE_FAILED");
310
+ outcome.status = "failed";
311
+ }
312
+ }
313
+ return outcome;
314
+ }
@@ -0,0 +1,111 @@
1
+ import { createHash } from "node:crypto";
2
+ import { validateAgentSuccessTask } from "../../../evaluation/agentSuccess/index.js";
3
+ import { AGENT_SUCCESS_RATE_TREATMENT_IDS } from "./metadata.js";
4
+ export const CAMPAIGN_IDENTITY_VERSION = "my-dev-kit-lab-agent-success-rate-campaign-identity-v1";
5
+ export const CAMPAIGN_COMPONENTS = ["corpus", "tasks", "projects", "checks", "behavior", "context", "retrieval", "execution", "providerBuild"];
6
+ export const CAMPAIGN_SOURCE_FILES = ["src/agents/types.ts", "src/agents/normalizeAgentTelemetry.ts", "src/agents/parseAgentTokenUsage.ts", "src/agents/runAgentPrompt.ts", "src/agents/adapters/codexAdapter.ts", "src/agents/adapters/claudeAdapter.ts", "src/evaluation/classifyAgentRunOutcome.ts", "src/experiments/plugins/agentSuccessRate/execution.ts", "src/experiments/plugins/agentSuccessRate/realAgentExecution.ts", "src/experiments/plugins/agentSuccessRate/contextGeneration.ts", "src/experiments/plugins/agentSuccessRate/repairExecution.ts", "src/experiments/plugins/agentSuccessRate/repairPolicy.ts", "src/experiments/plugins/agentSuccessRate/analysis.ts", "src/experiments/plugins/agentSuccessRate/plugin.ts"];
7
+ /** Additional transitive execution/safety owners; a missing source contract cannot certify reuse. */
8
+ export const CAMPAIGN_DEPENDENCY_FILES = ["src/experiments/plugins/agentSuccessRate/executionTypes.ts", "src/experiments/plugins/agentSuccessRate/analysisTypes.ts", "src/experiments/plugins/agentSuccessRate/attemptEvidence.ts", "src/experiments/plugins/agentSuccessRate/campaignIdentity.ts", "src/experiments/plugins/agentSuccessRate/campaignCheckpoint.ts", "src/experiments/plugins/agentSuccessRate/campaignCheckpointStore.ts", "src/evaluation/agentSuccess/patchTypes.ts", "src/evaluation/agentSuccess/taskTypes.ts", "src/evaluation/agentSuccess/verificationTypes.ts", "src/evaluation/agentSuccess/corpusTypes.ts", "src/evaluation/benchmarkSandbox/types.ts", "src/evaluation/benchmarkSandbox/errors.ts", "src/evaluation/changeSet/types.ts", "src/agents/agentRegistry.ts", "src/core/pathSafety.ts", "src/core/runMeasuredCommand.ts", "src/core/resolveCommand.ts", "src/core/processTree.ts", "src/core/fileGlobs.ts", "src/core/countTokens.ts", "src/core/commandLine.ts", "src/runtime/managedProcess.ts", "src/evaluation/runMyDevKitRetrieval.ts", "src/evaluation/agentSuccess/assessBaseline.ts", "src/evaluation/agentSuccess/applyPatchToSandbox.ts", "src/evaluation/agentSuccess/extractPatchCandidate.ts", "src/evaluation/agentSuccess/parseUnifiedDiff.ts", "src/evaluation/agentSuccess/runVerificationCheck.ts", "src/evaluation/agentSuccess/taskPaths.ts", "src/evaluation/agentSuccess/validatePatchPolicy.ts", "src/evaluation/agentSuccess/validateAgentSuccessTask.ts", "src/evaluation/agentSuccess/readAgentSuccessCorpus.ts", "src/evaluation/agentSuccess/validateAgentSuccessCorpus.ts", "src/evaluation/benchmarkSandbox/createBenchmarkSandbox.ts", "src/evaluation/benchmarkSandbox/removeBenchmarkSandbox.ts", "src/evaluation/benchmarkSandbox/pathPolicy.ts", "src/evaluation/benchmarkSandbox/treeSnapshot.ts", "src/evaluation/benchmarkSandbox/gitExecutor.ts", "src/evaluation/benchmarkSandbox/minimalHostEnv.ts", "src/evaluation/changeSet/captureChangeSet.ts", "src/experiments/plugins/agentSuccessRate/agentTaskProjection.ts", "src/experiments/plugins/agentSuccessRate/realAgentPrompt.ts", "src/experiments/plugins/agentSuccessRate/repairFeedback.ts", "src/experiments/plugins/agentSuccessRate/repairAnalysis.ts", "src/experiments/plugins/agentSuccessRate/metadata.ts", "src/experiments/plugins/agentSuccessRate/config.ts", "src/experiments/plugins/agentSuccessRate/executionArtifact.ts", "src/experiments/plugins/agentSuccessRate/analysisArtifact.ts", "src/experiments/outputPaths.ts"];
9
+ export function campaignAssert(condition, code = "INVALID_CHECKPOINT") {
10
+ if (!condition)
11
+ throw new Error(code);
12
+ }
13
+ export function campaignHash(bytes) { return createHash("sha256").update(bytes).digest("hex"); }
14
+ export function isCampaignDigest(value) { return typeof value === "string" && /^[a-f0-9]{64}$/.test(value); }
15
+ export function campaignIdentifier(value) { return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(value) && value !== "." && value !== ".."; }
16
+ /** Bounded finite JSON canonicalization; arrays retain semantic order. No implicit undefined/NaN coercion. */
17
+ export function canonicalCampaignJson(value) {
18
+ let visited = 0;
19
+ const encode = (v, depth) => {
20
+ campaignAssert(++visited <= 200_000 && depth <= 24, "DATA_BOUND");
21
+ if (v === null || typeof v === "boolean")
22
+ return JSON.stringify(v);
23
+ if (typeof v === "number") {
24
+ campaignAssert(Number.isFinite(v));
25
+ return JSON.stringify(v);
26
+ }
27
+ if (typeof v === "string") {
28
+ campaignAssert(v.length <= 1_048_576, "DATA_BOUND");
29
+ return JSON.stringify(v);
30
+ }
31
+ if (Array.isArray(v)) {
32
+ campaignAssert(v.length <= 10_000, "DATA_BOUND");
33
+ return `[${v.map((x) => encode(x, depth + 1)).join(",")}]`;
34
+ }
35
+ campaignAssert(typeof v === "object" && v !== null && Object.getPrototypeOf(v) === Object.prototype);
36
+ return `{${Object.keys(v).sort().map((k) => `${JSON.stringify(k)}:${encode(v[k], depth + 1)}`).join(",")}}`;
37
+ };
38
+ return encode(value, 0);
39
+ }
40
+ export function campaignExact(value, keys) {
41
+ campaignAssert(typeof value === "object" && value !== null && !Array.isArray(value));
42
+ campaignAssert(Object.keys(value).sort().join("\0") === [...keys].sort().join("\0"));
43
+ }
44
+ export function validateCampaignIdentity(value) {
45
+ campaignExact(value, ["schemaVersion", "algorithm", "pluginContract", "digest", "selected", "treatmentOrder", "config", "components"]);
46
+ campaignAssert(value.schemaVersion === CAMPAIGN_IDENTITY_VERSION && value.algorithm === "sha256" && value.pluginContract === "agent-success-rate/1.0.0", "INCOMPATIBLE_IDENTITY");
47
+ campaignAssert(Array.isArray(value.selected) && value.selected.length > 0 && value.selected.length <= 1000);
48
+ const ids = new Set();
49
+ for (const row of value.selected) {
50
+ campaignExact(row, ["caseId", "projectId", "taskDigest"]);
51
+ campaignAssert(campaignIdentifier(row.caseId) && campaignIdentifier(row.projectId) && isCampaignDigest(row.taskDigest) && !ids.has(row.caseId));
52
+ ids.add(row.caseId);
53
+ }
54
+ campaignAssert(canonicalCampaignJson(value.treatmentOrder) === canonicalCampaignJson(AGENT_SUCCESS_RATE_TREATMENT_IDS));
55
+ campaignExact(value.config, ["providerId", "timeoutMs", "repairAttempts"]);
56
+ campaignAssert(["codex", "claude", "deterministic-fixture"].includes(String(value.config.providerId)) && Number.isSafeInteger(value.config.timeoutMs) && Number(value.config.timeoutMs) > 0 && Number(value.config.timeoutMs) <= 1_800_000 && [0, 1, 2].includes(Number(value.config.repairAttempts)) && typeof value.config.repairAttempts === "number");
57
+ campaignExact(value.components, CAMPAIGN_COMPONENTS);
58
+ for (const name of CAMPAIGN_COMPONENTS) {
59
+ const component = value.components[name];
60
+ campaignExact(component, ["version", "digest"]);
61
+ campaignAssert(component.version === "1" && (component.digest === null || isCampaignDigest(component.digest)));
62
+ }
63
+ const { digest, ...body } = value;
64
+ campaignAssert(isCampaignDigest(digest) && digest === campaignHash(canonicalCampaignJson(body)), "IDENTITY_INTEGRITY");
65
+ }
66
+ /** Trusted caller supplies current corpus/project/source bytes. Never reads paths, executes a provider, or stores bodies. */
67
+ export function createCampaignIdentity(input) {
68
+ campaignAssert(input.tasks.length > 0 && input.tasks.length <= 1000);
69
+ input.tasks.forEach((t) => campaignAssert(validateAgentSuccessTask(t).ok));
70
+ const digest = (v) => campaignHash(canonicalCampaignJson(v));
71
+ const manifest = (files) => {
72
+ campaignAssert(files.length <= 10_000 && new Set(files.map((f) => f.path)).size === files.length);
73
+ return files.map((f) => { campaignAssert(typeof f.path === "string" && f.path.length <= 512 && !f.path.includes("\\") && !f.path.includes(":") && !f.path.startsWith("/") && f.path.split("/").every((p) => p !== "" && p !== "." && p !== "..") && !f.path.includes("\0")); return { path: f.path, digest: campaignHash(f.bytes) }; }).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
74
+ };
75
+ let source = null;
76
+ if (input.sourceFiles !== null) {
77
+ campaignAssert([...CAMPAIGN_SOURCE_FILES, ...CAMPAIGN_DEPENDENCY_FILES].every((required) => input.sourceFiles.some((f) => f.path === required)), "SOURCE_CONTRACT_MISSING");
78
+ source = digest(manifest(input.sourceFiles));
79
+ }
80
+ let projects = null;
81
+ if (input.projects !== null) {
82
+ campaignAssert([...input.projects.map((p) => p.projectId)].sort().join("\0") === [...new Set(input.tasks.map((t) => t.benchmarkProject))].sort().join("\0"));
83
+ projects = digest(input.projects.map((p) => ({ projectId: p.projectId, files: manifest(p.files) })).sort((a, b) => a.projectId < b.projectId ? -1 : a.projectId > b.projectId ? 1 : 0));
84
+ }
85
+ const values = { corpus: input.corpusBytes === null ? null : campaignHash(input.corpusBytes), tasks: digest(input.tasks), projects, checks: digest(input.tasks.map((t) => ({ id: t.id, task: t.taskChecks, regression: t.regressionChecks, protected: t.protectedFiles }))), behavior: digest(input.tasks.map((t) => ({ id: t.id, facts: t.behaviorFacts, expected: t.expectedEditFiles, allowed: t.allowedEditFiles }))), context: input.contextConfiguration === null ? null : digest(input.contextConfiguration), retrieval: input.retrievalConfiguration === null ? null : digest(input.retrievalConfiguration), execution: source, providerBuild: input.config.providerId === "deterministic-fixture" ? digest("no-provider-invocation-v1") : input.verifiedProviderObservation === null ? null : campaignHash(input.verifiedProviderObservation) };
86
+ const body = { schemaVersion: CAMPAIGN_IDENTITY_VERSION, algorithm: "sha256", pluginContract: "agent-success-rate/1.0.0", selected: input.tasks.map((t) => ({ caseId: t.id, projectId: t.benchmarkProject, taskDigest: digest(t) })), treatmentOrder: [...AGENT_SUCCESS_RATE_TREATMENT_IDS], config: structuredClone(input.config), components: Object.fromEntries(CAMPAIGN_COMPONENTS.map((key) => [key, { version: "1", digest: values[key] }])) };
87
+ const result = { ...body, digest: digest(body) };
88
+ validateCampaignIdentity(result);
89
+ return result;
90
+ }
91
+ export function compareCampaignIdentity(left, right) {
92
+ try {
93
+ validateCampaignIdentity(left);
94
+ validateCampaignIdentity(right);
95
+ }
96
+ catch {
97
+ return "UNVERIFIABLE";
98
+ }
99
+ if (canonicalCampaignJson(left.selected) !== canonicalCampaignJson(right.selected) || canonicalCampaignJson(left.config) !== canonicalCampaignJson(right.config))
100
+ return "MISMATCH";
101
+ let missing = false;
102
+ for (const name of CAMPAIGN_COMPONENTS) {
103
+ const a = left.components[name];
104
+ const b = right.components[name];
105
+ if (a.digest === null || b.digest === null)
106
+ missing = true;
107
+ else if (a.version !== b.version || a.digest !== b.digest)
108
+ return "MISMATCH";
109
+ }
110
+ return missing ? "UNVERIFIABLE" : "MATCH";
111
+ }
@@ -0,0 +1,175 @@
1
+ import { lstat, readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { isSameOrInside, resolvePhysicalPath } from "../../../evaluation/benchmarkSandbox/pathPolicy.js";
4
+ import { normalizeAgentDurationV091 as normalizedDuration, normalizeAgentTokenUsageV091 as normalizedTokens } from "../../../agents/normalizeAgentTelemetry.js";
5
+ import { validateAgentSuccessRateExecutionArtifact } from "./executionArtifact.js";
6
+ import { validateAgentSuccessRateAnalysisArtifact, validateAgentSuccessRateArtifactFamily } from "./analysisArtifact.js";
7
+ import { readCampaignCheckpointV2 } from "./campaignCheckpointStore.js";
8
+ import { campaignAssert, campaignExact, campaignHash, campaignIdentifier, canonicalCampaignJson, isCampaignDigest } from "./campaignIdentity.js";
9
+ import { CAMPAIGN_CHECKPOINT_SCHEMA_V2 } from "./campaignRecovery.js";
10
+ import { campaignAttemptTelemetry, classifyCampaignEvidence, CAMPAIGN_QUANTITIES, QUALITY_REASONS } from "./campaignEvidenceQuality.js";
11
+ export const CAMPAIGN_PROGRESS_SCHEMA = "my-dev-kit-lab-agent-success-rate-campaign-progress-v1";
12
+ export const CAMPAIGN_UNIT_STATES = ["pending", "in-progress", "completed", "paused-limit", "incomplete", "uncertain"];
13
+ export const CAMPAIGN_LIMITATIONS = [
14
+ "Completed evaluation does not mean successful task outcome. Trusted task checks determine success.",
15
+ "Matched subset values exclude unfinished or unavailable cases; pending outcomes are never failures.",
16
+ "Differences are context-pack minus raw-full-file, with no ranking, composite score, significance test or causal inference.",
17
+ "Duration is Lab wall-clock time, not provider-native execution time.",
18
+ "Token channels do not prove direct measurement of every field. Estimates are not billing usage.",
19
+ "Historical provider-limit epochs are operational history; only the authorized evaluated epoch contributes scientific evidence.",
20
+ "Deterministic-fixture mode validates the evaluation pipeline; it measures no coding agent or context selection effect."
21
+ ];
22
+ const snapshots = new WeakMap();
23
+ export function assertValidatedCampaignProgress(snapshot, boundary) {
24
+ const proof = snapshots.get(snapshot);
25
+ campaignAssert(proof && proof.boundary.outputRoot === boundary.outputRoot && proof.boundary.toolRoot === boundary.toolRoot && proof.canonical === canonicalCampaignJson(snapshot.model), "UNVALIDATED_PROGRESS_SNAPSHOT");
26
+ validateCampaignProgress(snapshot.model);
27
+ }
28
+ function caseState(states) {
29
+ if (states.every(s => s === "completed"))
30
+ return "completed";
31
+ if (states.some(s => ["in-progress", "incomplete", "uncertain"].includes(s)))
32
+ return "blockedUncertain";
33
+ if (states.includes("paused-limit"))
34
+ return "paused";
35
+ return states.includes("completed") ? "partiallyCompleted" : "pending";
36
+ }
37
+ /** Filesystem validation is mandatory; an absent, corrupt or untrusted checkpoint never becomes empty progress. */
38
+ export async function readCampaignProgress(boundary, identity, tasks) {
39
+ const stored = await readCampaignCheckpointV2(boundary, identity, tasks);
40
+ campaignAssert(stored.checkpoint && stored.identityVerification === "MATCH", "PROGRESS_CHECKPOINT_UNAVAILABLE");
41
+ const cp = stored.checkpoint;
42
+ // Presence is a blocker, never evidence of a stale owner or permission to remove its marker.
43
+ const present = async (file) => {
44
+ try {
45
+ const s = await lstat(file);
46
+ campaignAssert(s.isFile() && !s.isSymbolicLink(), "PROGRESS_OWNERSHIP_UNSAFE");
47
+ return true;
48
+ }
49
+ catch (e) {
50
+ if (e.code === "ENOENT")
51
+ return false;
52
+ throw e;
53
+ }
54
+ };
55
+ const publicationUnresolved = stored.temporaryFiles.length > 0 || await present(path.join(boundary.outputRoot, "campaign-checkpoints-v2", identity.digest, "writer.json"));
56
+ const dispatchPresent = await present(path.join(boundary.outputRoot, "campaign-dispatch.json"));
57
+ const cases = tasks.map((task, i) => {
58
+ const units = cp.units.slice(i * 2, i * 2 + 2);
59
+ return { caseId: task.id, state: caseState(units.map(u => u.state)), treatments: units.map(u => ({ treatmentId: u.treatmentId, state: u.state, evaluatedTaskSuccess: u.completion?.taskSuccess ?? null, epochCount: u.epochs.length, historicalProviderLimitCount: u.epochs.slice(0, -1).filter(e => e.terminal?.reason === "provider-limit").length,
60
+ diagnostics: (u.state === "paused-limit" ? ["PROVIDER_LIMIT"] : ["in-progress", "uncertain"].includes(u.state) ? ["INVOCATION_UNCERTAIN"] : u.state === "incomplete" ? ["INCOMPLETE_EVALUATION"] : []), attempts: u.completion ? campaignAttemptTelemetry(u.completion.evidence) : [] })) };
61
+ });
62
+ const unitCounts = Object.fromEntries(CAMPAIGN_UNIT_STATES.map(s => [s, cp.units.filter(u => u.state === s).length]));
63
+ const caseCounts = Object.fromEntries(["completed", "partiallyCompleted", "pending", "paused", "blockedUncertain"].map(s => [s, cases.filter(c => c.state === s).length]));
64
+ const knownUncertainty = caseCounts.blockedUncertain > 0 || publicationUnresolved || dispatchPresent;
65
+ const diagnostics = [];
66
+ if (publicationUnresolved)
67
+ diagnostics.push("CHECKPOINT_PUBLICATION_UNRESOLVED");
68
+ if (dispatchPresent)
69
+ diagnostics.push("DISPATCH_OWNERSHIP_PRESENT");
70
+ if (unitCounts["in-progress"] || unitCounts.uncertain)
71
+ diagnostics.push("INVOCATION_UNCERTAIN");
72
+ if (unitCounts.incomplete)
73
+ diagnostics.push("INCOMPLETE_EVALUATION");
74
+ if (unitCounts["paused-limit"])
75
+ diagnostics.push("PROVIDER_LIMIT");
76
+ const state = knownUncertainty ? "blocked-uncertain" : unitCounts["paused-limit"] ? "paused-limit" : unitCounts.completed === cp.units.length ? "complete" : unitCounts.completed ? "partial" : "pending";
77
+ const model = { schemaVersion: CAMPAIGN_PROGRESS_SCHEMA, campaignIdentity: cp.identity.digest, checkpointSchemaVersion: cp.schemaVersion, checkpointGeneration: cp.generation, checkpointRevision: cp.integrity, executionMode: cp.identity.config.providerId === "deterministic-fixture" ? "deterministic-fixture" : "provider", selectedCaseCount: tasks.length, totalTreatmentUnits: cp.units.length, treatmentOrder: ["raw-full-file", "context-pack"], unitCounts, caseCounts, state, completedCaseIds: cases.filter(c => c.state === "completed").map(c => c.caseId), unfinishedCaseIds: cases.filter(c => c.state !== "completed").map(c => c.caseId), cases, knownProviderLimit: unitCounts["paused-limit"] > 0, knownUncertainty, diagnostics, scientificCompleteness: unitCounts.completed === cp.units.length ? "complete" : unitCounts.completed ? "partial" : "unavailable", finalScientificArtifactsAvailable: cp.finalization !== null, comparisons: classifyCampaignEvidence(cp, tasks), limitations: [...CAMPAIGN_LIMITATIONS] };
78
+ validateCampaignProgress(model);
79
+ const snapshot = { model };
80
+ snapshots.set(snapshot, { boundary: { ...boundary }, canonical: canonicalCampaignJson(model), checkpoint: cp });
81
+ return snapshot;
82
+ }
83
+ /** Load only the existing finalized scientific family, bound to the exact snapshot's content proofs. */
84
+ export async function readCampaignProgressScientificFamily(snapshot, boundary) {
85
+ assertValidatedCampaignProgress(snapshot, boundary);
86
+ const cp = snapshots.get(snapshot).checkpoint;
87
+ if (!cp.finalization)
88
+ return null;
89
+ const load = async (name) => {
90
+ const ref = cp.finalization.artifacts.find(a => a.path === name);
91
+ const file = path.join(boundary.outputRoot, name), stat = await lstat(file);
92
+ const [physicalRoot, physicalFile] = await Promise.all([resolvePhysicalPath(boundary.outputRoot), resolvePhysicalPath(file)]);
93
+ campaignAssert(stat.isFile() && !stat.isSymbolicLink() && stat.size === ref.bytes && isSameOrInside(physicalRoot, physicalFile) && path.dirname(physicalFile) === physicalRoot, "SCIENTIFIC_ARTIFACT_UNSAFE");
94
+ const bytes = await readFile(file);
95
+ campaignAssert(bytes.length === ref.bytes && campaignHash(bytes) === ref.sha256, "SCIENTIFIC_ARTIFACT_CHANGED");
96
+ return JSON.parse(bytes.toString("utf8"));
97
+ };
98
+ const execution = await load("agent-success-rate-execution.json");
99
+ const analysis = await load("agent-success-rate-analysis.json");
100
+ campaignAssert([...validateAgentSuccessRateExecutionArtifact(execution), ...validateAgentSuccessRateAnalysisArtifact(analysis), ...validateAgentSuccessRateArtifactFamily(execution, analysis)].length === 0, "SCIENTIFIC_FAMILY_INVALID");
101
+ return { execution, analysis };
102
+ }
103
+ /** Closed durable schema, including reconciliation of identities, counts, quality and measurement availability. */
104
+ export function validateCampaignProgress(value) {
105
+ campaignExact(value, ["schemaVersion", "campaignIdentity", "checkpointSchemaVersion", "checkpointGeneration", "checkpointRevision", "executionMode", "selectedCaseCount", "totalTreatmentUnits", "treatmentOrder", "unitCounts", "caseCounts", "state", "completedCaseIds", "unfinishedCaseIds", "cases", "knownProviderLimit", "knownUncertainty", "diagnostics", "scientificCompleteness", "finalScientificArtifactsAvailable", "comparisons", "limitations"]);
106
+ const m = value;
107
+ campaignAssert(m.schemaVersion === CAMPAIGN_PROGRESS_SCHEMA && m.checkpointSchemaVersion === CAMPAIGN_CHECKPOINT_SCHEMA_V2 && isCampaignDigest(m.campaignIdentity) && isCampaignDigest(m.checkpointRevision), "INVALID_PROGRESS_SCHEMA");
108
+ const count = (n, max = 2000) => campaignAssert(Number.isSafeInteger(n) && Number(n) >= 0 && Number(n) <= max, "INVALID_PROGRESS_COUNT");
109
+ count(m.checkpointGeneration, 1_000_000);
110
+ campaignAssert(m.checkpointGeneration > 0);
111
+ count(m.selectedCaseCount, 1000);
112
+ campaignAssert(m.selectedCaseCount > 0 && m.totalTreatmentUnits === 2 * m.selectedCaseCount && JSON.stringify(m.treatmentOrder) === '["raw-full-file","context-pack"]');
113
+ campaignAssert(["provider", "deterministic-fixture"].includes(m.executionMode) && Array.isArray(m.cases) && m.cases.length === m.selectedCaseCount);
114
+ campaignExact(m.unitCounts, CAMPAIGN_UNIT_STATES);
115
+ campaignExact(m.caseCounts, ["completed", "partiallyCompleted", "pending", "paused", "blockedUncertain"]);
116
+ const ids = [], states = [];
117
+ for (const c of m.cases) {
118
+ campaignExact(c, ["caseId", "state", "treatments"]);
119
+ campaignAssert(campaignIdentifier(c.caseId) && !ids.includes(c.caseId) && Array.isArray(c.treatments) && c.treatments.length === 2);
120
+ ids.push(c.caseId);
121
+ c.treatments.forEach((t, i) => {
122
+ campaignExact(t, ["treatmentId", "state", "evaluatedTaskSuccess", "epochCount", "historicalProviderLimitCount", "diagnostics", "attempts"]);
123
+ campaignAssert(t.treatmentId === m.treatmentOrder[i] && CAMPAIGN_UNIT_STATES.includes(t.state));
124
+ states.push(t.state);
125
+ count(t.epochCount, 2);
126
+ count(t.historicalProviderLimitCount, 1);
127
+ campaignAssert(t.historicalProviderLimitCount < Math.max(1, t.epochCount) && (t.state === "completed" ? typeof t.evaluatedTaskSuccess === "boolean" : t.evaluatedTaskSuccess === null));
128
+ const expected = t.state === "paused-limit" ? ["PROVIDER_LIMIT"] : ["in-progress", "uncertain"].includes(t.state) ? ["INVOCATION_UNCERTAIN"] : t.state === "incomplete" ? ["INCOMPLETE_EVALUATION"] : [];
129
+ campaignAssert(JSON.stringify(t.diagnostics) === JSON.stringify(expected) && Array.isArray(t.attempts) && t.attempts.length <= 3 && (t.state === "completed" ? t.attempts.length > 0 : t.attempts.length === 0));
130
+ t.attempts.forEach((a, j) => {
131
+ campaignExact(a, ["attemptNumber", "providerInvoked", "duration", "tokens", "tokenInterpretation"]);
132
+ campaignAssert(a.attemptNumber === j + 1 && typeof a.providerInvoked === "boolean");
133
+ campaignExact(a.duration, ["durationMs", "source", "reason"]);
134
+ campaignAssert(canonicalCampaignJson(a.duration) === canonicalCampaignJson(normalizedDuration(a.duration.durationMs)));
135
+ campaignExact(a.tokens, ["source", "reliability", "evidenceLevel", "classificationReason", "numericAvailability", "condition", "totalTokens", "inputTokens", "outputTokens", "cachedInputTokens", "reasoningTokens", "numericReasons"]);
136
+ campaignAssert(["provider-reported", "cli-json", "agent-reported", "otel", "estimated-from-text", "unavailable"].includes(a.tokens.source) && ["high", "medium", "low", "unavailable"].includes(a.tokens.reliability));
137
+ const n = normalizedTokens({ source: a.tokens.source, ...(a.tokens.totalTokens === null ? {} : { totalTokens: a.tokens.totalTokens }), ...(a.tokens.inputTokens === null ? {} : { inputTokens: a.tokens.inputTokens }), ...(a.tokens.outputTokens === null ? {} : { outputTokens: a.tokens.outputTokens }) }, a.tokens.reliability);
138
+ campaignAssert(canonicalCampaignJson(a.tokens) === canonicalCampaignJson(n));
139
+ campaignAssert(a.tokenInterpretation === (a.tokens.source === "estimated-from-text" ? "estimated" : a.tokens.totalTokens === null ? "unavailable" : "recorded-with-channel-provenance"));
140
+ });
141
+ });
142
+ campaignAssert(c.state === caseState(c.treatments.map(t => t.state)));
143
+ }
144
+ for (const s of CAMPAIGN_UNIT_STATES) {
145
+ count(m.unitCounts[s]);
146
+ campaignAssert(m.unitCounts[s] === states.filter(t => t === s).length);
147
+ }
148
+ for (const s of Object.keys(m.caseCounts)) {
149
+ count(m.caseCounts[s]);
150
+ campaignAssert(m.caseCounts[s] === m.cases.filter(c => c.state === s).length);
151
+ }
152
+ campaignAssert(JSON.stringify(m.completedCaseIds) === JSON.stringify(m.cases.filter(c => c.state === "completed").map(c => c.caseId)) && JSON.stringify(m.unfinishedCaseIds) === JSON.stringify(m.cases.filter(c => c.state !== "completed").map(c => c.caseId)));
153
+ campaignAssert(m.knownProviderLimit === (m.unitCounts["paused-limit"] > 0) && typeof m.knownUncertainty === "boolean" && (m.caseCounts.blockedUncertain === 0 || m.knownUncertainty));
154
+ campaignAssert(Array.isArray(m.diagnostics) && new Set(m.diagnostics).size === m.diagnostics.length && m.diagnostics.every(d => ["CHECKPOINT_PUBLICATION_UNRESOLVED", "DISPATCH_OWNERSHIP_PRESENT", "INVOCATION_UNCERTAIN", "INCOMPLETE_EVALUATION", "PROVIDER_LIMIT"].includes(d)));
155
+ campaignAssert(m.knownUncertainty === (m.caseCounts.blockedUncertain > 0 || m.diagnostics.includes("CHECKPOINT_PUBLICATION_UNRESOLVED") || m.diagnostics.includes("DISPATCH_OWNERSHIP_PRESENT")) && m.diagnostics.includes("INVOCATION_UNCERTAIN") === (m.unitCounts["in-progress"] + m.unitCounts.uncertain > 0) && m.diagnostics.includes("INCOMPLETE_EVALUATION") === (m.unitCounts.incomplete > 0) && m.diagnostics.includes("PROVIDER_LIMIT") === m.knownProviderLimit);
156
+ campaignAssert(m.state === (m.knownUncertainty ? "blocked-uncertain" : m.knownProviderLimit ? "paused-limit" : m.unitCounts.completed === m.totalTreatmentUnits ? "complete" : m.unitCounts.completed ? "partial" : "pending"));
157
+ campaignAssert(m.scientificCompleteness === (m.unitCounts.completed === m.totalTreatmentUnits ? "complete" : m.unitCounts.completed ? "partial" : "unavailable") && typeof m.finalScientificArtifactsAvailable === "boolean" && (!m.finalScientificArtifactsAvailable || m.scientificCompleteness === "complete"));
158
+ campaignAssert(Array.isArray(m.comparisons) && m.comparisons.length === CAMPAIGN_QUANTITIES.length);
159
+ m.comparisons.forEach((q, i) => {
160
+ campaignExact(q, ["quantity", "basis", "measurementBasis", "unit", "quality", "selectedCaseCount", "matchedCaseIds", "excludedCaseIds", "rawFullFileMean", "contextPackMean", "meanDifference", "reasons", "reasonExplanations"]);
161
+ campaignAssert(q.quantity === CAMPAIGN_QUANTITIES[i] && q.selectedCaseCount === ids.length && Array.isArray(q.matchedCaseIds) && new Set(q.matchedCaseIds).size === q.matchedCaseIds.length);
162
+ campaignAssert(JSON.stringify(q.matchedCaseIds) === JSON.stringify(ids.filter(id => q.matchedCaseIds.includes(id))) && q.matchedCaseIds.every(id => m.completedCaseIds.includes(id)) && JSON.stringify(q.excludedCaseIds) === JSON.stringify(ids.filter(id => !q.matchedCaseIds.includes(id))));
163
+ const token = q.quantity.endsWith("Tokens"), duration = q.quantity.endsWith("Duration");
164
+ campaignAssert(q.unit === (token ? "tokens" : duration ? "ms" : q.quantity === "regressionFailureCount" ? "count" : "ratio"));
165
+ campaignAssert(q.basis === (q.quantity.startsWith("first") || q.quantity === "initialTaskSuccess" ? "first-attempt" : q.quantity.startsWith("total") ? "total-across-attempts" : "final-attempt") && q.measurementBasis === (token ? "recorded-token-channel" : duration ? "lab-wall-clock" : q.quantity.endsWith("TaskSuccess") ? "trusted-task-evaluation" : "trusted-check-evaluation"));
166
+ campaignAssert(q.quality === (q.matchedCaseIds.length === 0 ? "unavailable" : q.excludedCaseIds.length || token ? "partial" : "strong"));
167
+ for (const n of [q.rawFullFileMean, q.contextPackMean, q.meanDifference])
168
+ campaignAssert(q.quality === "unavailable" ? n === null : typeof n === "number" && Number.isFinite(n));
169
+ campaignAssert(Array.isArray(q.reasons) && new Set(q.reasons).size === q.reasons.length && q.reasons.every(r => Object.hasOwn(QUALITY_REASONS, r)));
170
+ campaignAssert(JSON.stringify(q.reasonExplanations) === JSON.stringify(q.reasons.map(r => QUALITY_REASONS[r])));
171
+ campaignAssert(q.reasons.includes("NO_MATCHED_OBSERVATIONS") === (q.matchedCaseIds.length === 0) && q.reasons.includes("SELECTED_CASES_EXCLUDED") === (q.excludedCaseIds.length > 0) && (!token || q.quality === "unavailable" || q.reasons.includes("TOKEN_FIELD_PROVENANCE_UNPROVEN")));
172
+ });
173
+ campaignAssert(JSON.stringify(m.limitations) === JSON.stringify(CAMPAIGN_LIMITATIONS));
174
+ canonicalCampaignJson(m);
175
+ }