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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/README.md +20 -4
  3. package/benchmarks/contracts/agent-success-rate-project-profiles.json +33 -0
  4. package/benchmarks/contracts/agent-success-rate-tasks.json +671 -0
  5. package/benchmarks/projects/agent-success-inventory-node/.gitattributes +2 -0
  6. package/benchmarks/projects/agent-success-inventory-node/README.md +74 -0
  7. package/benchmarks/projects/agent-success-inventory-node/package.json +14 -0
  8. package/benchmarks/projects/agent-success-inventory-node/src/fulfillmentReport.js +38 -0
  9. package/benchmarks/projects/agent-success-inventory-node/src/index.js +26 -0
  10. package/benchmarks/projects/agent-success-inventory-node/src/inventoryStore.js +114 -0
  11. package/benchmarks/projects/agent-success-inventory-node/src/quantity.js +19 -0
  12. package/benchmarks/projects/agent-success-inventory-node/src/reservationService.js +45 -0
  13. package/benchmarks/projects/agent-success-inventory-node/tests/quantity-edge.check.mjs +51 -0
  14. package/benchmarks/projects/agent-success-inventory-node/tests/quantity-primary.check.mjs +46 -0
  15. package/benchmarks/projects/agent-success-inventory-node/tests/regression.check.mjs +115 -0
  16. package/benchmarks/projects/agent-success-inventory-node/tests/report-edge.check.mjs +109 -0
  17. package/benchmarks/projects/agent-success-inventory-node/tests/report-primary.check.mjs +47 -0
  18. package/benchmarks/projects/agent-success-inventory-node/tests/reservation-edge.check.mjs +63 -0
  19. package/benchmarks/projects/agent-success-inventory-node/tests/reservation-primary.check.mjs +44 -0
  20. package/benchmarks/projects/agent-success-task-board-node/.gitattributes +2 -0
  21. package/benchmarks/projects/agent-success-task-board-node/README.md +77 -0
  22. package/benchmarks/projects/agent-success-task-board-node/package.json +14 -0
  23. package/benchmarks/projects/agent-success-task-board-node/src/index.js +24 -0
  24. package/benchmarks/projects/agent-success-task-board-node/src/projectSummary.js +15 -0
  25. package/benchmarks/projects/agent-success-task-board-node/src/taskService.js +58 -0
  26. package/benchmarks/projects/agent-success-task-board-node/src/taskStore.js +58 -0
  27. package/benchmarks/projects/agent-success-task-board-node/src/validation.js +31 -0
  28. package/benchmarks/projects/agent-success-task-board-node/tests/import-edge.check.mjs +65 -0
  29. package/benchmarks/projects/agent-success-task-board-node/tests/import-primary.check.mjs +31 -0
  30. package/benchmarks/projects/agent-success-task-board-node/tests/regression.check.mjs +107 -0
  31. package/benchmarks/projects/agent-success-task-board-node/tests/summary-edge.check.mjs +67 -0
  32. package/benchmarks/projects/agent-success-task-board-node/tests/summary-primary.check.mjs +54 -0
  33. package/benchmarks/projects/agent-success-task-board-node/tests/title-edge.check.mjs +39 -0
  34. package/benchmarks/projects/agent-success-task-board-node/tests/title-primary.check.mjs +29 -0
  35. package/dist/src/cli/help.js +54 -2
  36. package/dist/src/commands/runExperimentDescribeCommand.js +60 -2
  37. package/dist/src/commands/runExperimentRunCommand.js +208 -5
  38. package/dist/src/core/processTree.js +55 -0
  39. package/dist/src/core/runMeasuredCommand.js +104 -22
  40. package/dist/src/evaluation/agentSuccess/applyPatchToSandbox.js +37 -0
  41. package/dist/src/evaluation/agentSuccess/assessBaseline.js +23 -0
  42. package/dist/src/evaluation/agentSuccess/corpusTypes.js +74 -0
  43. package/dist/src/evaluation/agentSuccess/extractPatchCandidate.js +46 -0
  44. package/dist/src/evaluation/agentSuccess/index.js +14 -0
  45. package/dist/src/evaluation/agentSuccess/parseUnifiedDiff.js +210 -0
  46. package/dist/src/evaluation/agentSuccess/patchTypes.js +5 -0
  47. package/dist/src/evaluation/agentSuccess/readAgentSuccessCorpus.js +183 -0
  48. package/dist/src/evaluation/agentSuccess/runVerificationCheck.js +100 -0
  49. package/dist/src/evaluation/agentSuccess/taskPaths.js +34 -0
  50. package/dist/src/evaluation/agentSuccess/taskTypes.js +14 -0
  51. package/dist/src/evaluation/agentSuccess/validateAgentSuccessCorpus.js +307 -0
  52. package/dist/src/evaluation/agentSuccess/validateAgentSuccessTask.js +297 -0
  53. package/dist/src/evaluation/agentSuccess/validatePatchPolicy.js +66 -0
  54. package/dist/src/evaluation/agentSuccess/verificationTypes.js +1 -0
  55. package/dist/src/evaluation/benchmarkSandbox/createBenchmarkSandbox.js +127 -0
  56. package/dist/src/evaluation/benchmarkSandbox/errors.js +11 -0
  57. package/dist/src/evaluation/benchmarkSandbox/gitExecutor.js +60 -0
  58. package/dist/src/evaluation/benchmarkSandbox/index.js +8 -0
  59. package/dist/src/evaluation/benchmarkSandbox/minimalHostEnv.js +37 -0
  60. package/dist/src/evaluation/benchmarkSandbox/pathPolicy.js +49 -0
  61. package/dist/src/evaluation/benchmarkSandbox/removeBenchmarkSandbox.js +74 -0
  62. package/dist/src/evaluation/benchmarkSandbox/treeSnapshot.js +57 -0
  63. package/dist/src/evaluation/benchmarkSandbox/types.js +3 -0
  64. package/dist/src/evaluation/changeSet/captureChangeSet.js +98 -0
  65. package/dist/src/evaluation/changeSet/index.js +2 -0
  66. package/dist/src/evaluation/changeSet/types.js +9 -0
  67. package/dist/src/evaluation/runMyDevKitRetrieval.js +1 -0
  68. package/dist/src/experiments/defaultRegistry.js +4 -0
  69. package/dist/src/experiments/plugins/agentSuccessRate/agentTaskProjection.js +12 -0
  70. package/dist/src/experiments/plugins/agentSuccessRate/analysis.js +425 -0
  71. package/dist/src/experiments/plugins/agentSuccessRate/analysisArtifact.js +155 -0
  72. package/dist/src/experiments/plugins/agentSuccessRate/analysisTypes.js +65 -0
  73. package/dist/src/experiments/plugins/agentSuccessRate/attemptEvidence.js +7 -0
  74. package/dist/src/experiments/plugins/agentSuccessRate/config.js +123 -0
  75. package/dist/src/experiments/plugins/agentSuccessRate/contextGeneration.js +497 -0
  76. package/dist/src/experiments/plugins/agentSuccessRate/execution.js +441 -0
  77. package/dist/src/experiments/plugins/agentSuccessRate/executionArtifact.js +126 -0
  78. package/dist/src/experiments/plugins/agentSuccessRate/executionTypes.js +2 -0
  79. package/dist/src/experiments/plugins/agentSuccessRate/index.js +20 -0
  80. package/dist/src/experiments/plugins/agentSuccessRate/metadata.js +28 -0
  81. package/dist/src/experiments/plugins/agentSuccessRate/metrics.js +76 -0
  82. package/dist/src/experiments/plugins/agentSuccessRate/plugin.js +507 -0
  83. package/dist/src/experiments/plugins/agentSuccessRate/realAgentExecution.js +250 -0
  84. package/dist/src/experiments/plugins/agentSuccessRate/realAgentPrompt.js +43 -0
  85. package/dist/src/experiments/plugins/agentSuccessRate/repairAnalysis.js +148 -0
  86. package/dist/src/experiments/plugins/agentSuccessRate/repairExecution.js +103 -0
  87. package/dist/src/experiments/plugins/agentSuccessRate/repairFeedback.js +91 -0
  88. package/dist/src/experiments/plugins/agentSuccessRate/repairPolicy.js +88 -0
  89. package/dist/src/experiments/plugins/agentSuccessRate/types.js +1 -0
  90. package/dist/src/experiments/plugins/contextPackGeneration/analysis.js +157 -0
  91. package/dist/src/experiments/plugins/contextPackGeneration/analysisArtifact.js +22 -0
  92. package/dist/src/experiments/plugins/contextPackGeneration/analysisTypes.js +1 -0
  93. package/dist/src/experiments/plugins/contextPackGeneration/buildContextPack.js +84 -0
  94. package/dist/src/experiments/plugins/contextPackGeneration/config.js +39 -0
  95. package/dist/src/experiments/plugins/contextPackGeneration/execution.js +361 -0
  96. package/dist/src/experiments/plugins/contextPackGeneration/executionArtifact.js +17 -0
  97. package/dist/src/experiments/plugins/contextPackGeneration/executionTypes.js +11 -0
  98. package/dist/src/experiments/plugins/contextPackGeneration/identityEvidence.js +71 -0
  99. package/dist/src/experiments/plugins/contextPackGeneration/index.js +19 -0
  100. package/dist/src/experiments/plugins/contextPackGeneration/localSubjectExecution.js +146 -0
  101. package/dist/src/experiments/plugins/contextPackGeneration/localSubjectPrivacy.js +276 -0
  102. package/dist/src/experiments/plugins/contextPackGeneration/metadata.js +24 -0
  103. package/dist/src/experiments/plugins/contextPackGeneration/metrics.js +46 -0
  104. package/dist/src/experiments/plugins/contextPackGeneration/packArtifact.js +17 -0
  105. package/dist/src/experiments/plugins/contextPackGeneration/packEvidence.js +152 -0
  106. package/dist/src/experiments/plugins/contextPackGeneration/packSelectionPolicy.js +305 -0
  107. package/dist/src/experiments/plugins/contextPackGeneration/plugin.js +355 -0
  108. package/dist/src/experiments/plugins/contextPackGeneration/renderContextPack.js +61 -0
  109. package/dist/src/experiments/plugins/contextPackGeneration/types.js +29 -0
  110. package/dist/src/experiments/plugins/warmIndexReuse/plugin.js +2 -3
  111. package/dist/src/report/experiments/agentSuccessRateReportModel.js +6 -0
  112. package/dist/src/report/experiments/buildAgentSuccessRateReport.js +255 -0
  113. package/dist/src/report/experiments/buildContextPackGenerationReport.js +171 -0
  114. package/dist/src/report/experiments/buildPluginExperimentReport.js +49 -2
  115. package/dist/src/report/experiments/contextPackGenerationReportModel.js +9 -0
  116. package/dist/src/report/experiments/index.js +9 -0
  117. package/dist/src/report/experiments/loadContextPackArtifacts.js +43 -0
  118. package/dist/src/report/experiments/renderAgentSuccessRateHtml.js +169 -0
  119. package/dist/src/report/experiments/renderAgentSuccessRateText.js +139 -0
  120. package/dist/src/report/experiments/renderContextPackGenerationHtml.js +122 -0
  121. package/dist/src/report/experiments/renderContextPackGenerationText.js +101 -0
  122. package/dist/src/report/experiments/renderPluginExperimentReportHtml.js +6 -0
  123. package/dist/src/report/experiments/renderPluginExperimentReportText.js +12 -0
  124. package/dist/src/report/experiments/renderRetrievalQueryStrategyComparisonHtml.js +15 -15
  125. package/dist/src/report/experiments/writePluginExperimentReports.js +2 -0
  126. package/docs/METRICS.md +98 -1
  127. package/package.json +1 -1
@@ -0,0 +1,61 @@
1
+ /** Stable source boundary; it cannot be confused with Markdown code-fence nesting. */
2
+ export const CONTEXT_PACK_SOURCE_BEGIN = "<<<SOURCE";
3
+ export const CONTEXT_PACK_SOURCE_END = "SOURCE>>>";
4
+ export const CONTEXT_PACK_SECTION_HEADINGS = {
5
+ task: "## Task",
6
+ files: "## Relevant files",
7
+ symbols: "## Relevant symbols",
8
+ sourceSlices: "## Source slices",
9
+ callRelationships: "## Call relationships",
10
+ tests: "## Tests",
11
+ evidenceNotes: "## Evidence notes"
12
+ };
13
+ const lf = (text) => text.replace(/\r\n?/g, "\n");
14
+ function renderBody(id, lines, availability) {
15
+ const heading = CONTEXT_PACK_SECTION_HEADINGS[id];
16
+ if (lines.length > 0)
17
+ return [heading, ...lines].join("\n");
18
+ const { availability: state, reason } = availability[id];
19
+ const suffix = reason === null ? "" : `: ${reason}`;
20
+ const placeholder = state === "available" ? "(none)" : `(${state}${suffix})`;
21
+ return `${heading}\n${placeholder}`;
22
+ }
23
+ function renderSlice(slice) {
24
+ return [
25
+ `file: ${slice.file}`,
26
+ `lines: ${slice.startLine}-${slice.endLine}`,
27
+ `boundary: ${slice.boundaryKnown ? "known" : "unknown"}`,
28
+ `truncated: ${slice.truncated ? "yes" : "no"}`,
29
+ CONTEXT_PACK_SOURCE_BEGIN,
30
+ lf(slice.text),
31
+ CONTEXT_PACK_SOURCE_END
32
+ ].join("\n");
33
+ }
34
+ /** Deterministic, language-agnostic rendering. Source text is verbatim apart from line-ending normalization. */
35
+ export function renderContextPack(input) {
36
+ const availability = input.sectionAvailability;
37
+ const sections = {
38
+ task: `${CONTEXT_PACK_SECTION_HEADINGS.task}\nTitle: ${lf(input.task.title)}\nSummary: ${lf(input.task.summary)}`,
39
+ files: renderBody("files", input.files.map((file) => `- ${file.path}`), availability),
40
+ symbols: renderBody("symbols", input.symbols.map((symbol) => (symbol.file === null ? `- ${symbol.name}` : `- ${symbol.name} (${symbol.file})`)), availability),
41
+ sourceSlices: renderSourceSlices(input.sourceSlices, availability),
42
+ callRelationships: renderBody("callRelationships", input.callRelationships.map((call) => `${call.fromNodeId} -> ${call.toNodeId}`), availability),
43
+ tests: renderBody("tests", input.tests.map((test) => `- ${test.path}`), availability),
44
+ evidenceNotes: renderBody("evidenceNotes", input.evidenceNotes.map((code) => `- ${code}`), availability)
45
+ };
46
+ const renderedText = `${[
47
+ sections.task,
48
+ sections.files,
49
+ sections.symbols,
50
+ sections.sourceSlices,
51
+ sections.callRelationships,
52
+ sections.tests,
53
+ sections.evidenceNotes
54
+ ].join("\n\n")}\n`;
55
+ return { sections, renderedText };
56
+ }
57
+ function renderSourceSlices(slices, availability) {
58
+ if (slices.length === 0)
59
+ return renderBody("sourceSlices", [], availability);
60
+ return `${CONTEXT_PACK_SECTION_HEADINGS.sourceSlices}\n${slices.map(renderSlice).join("\n\n")}`;
61
+ }
@@ -0,0 +1,29 @@
1
+ /** Domain schema of the Lab-owned experimental context pack. It is a measurement artifact, not a production contract. */
2
+ export const CONTEXT_PACK_SCHEMA_VERSION = "my-dev-kit-lab-context-pack-experiment-v1";
3
+ /** Logical section order of the pack. */
4
+ export const CONTEXT_PACK_SECTION_IDS = [
5
+ "task",
6
+ "files",
7
+ "symbols",
8
+ "sourceSlices",
9
+ "callRelationships",
10
+ "tests",
11
+ "evidenceNotes"
12
+ ];
13
+ /**
14
+ * Closed fixed vocabulary. Only codes produced by the pure Batch 1 domain exist; no free-form warning text, and no
15
+ * execution, indexing, privacy or persistence failure codes.
16
+ */
17
+ export const CONTEXT_PACK_EVIDENCE_NOTE_CODES = [
18
+ "symbol-end-unknown",
19
+ "source-slice-cap-reached",
20
+ "total-source-line-cap-reached",
21
+ "source-slice-count-cap-reached",
22
+ "seed-cap-reached",
23
+ "file-cap-reached",
24
+ "symbol-cap-reached",
25
+ "test-file-cap-reached",
26
+ "call-relationship-cap-reached",
27
+ "invalid-repository-path-ignored",
28
+ "invalid-source-slice-ignored"
29
+ ];
@@ -42,9 +42,8 @@ export const warmIndexReusePlugin = {
42
42
  const startedAt = context.startedAt.toISOString();
43
43
  // A campaign preset selects campaign-aware case selection and real-agent evaluation for
44
44
  // exactly one provider; its absence preserves the legacy fake-agent path unchanged. Real-agent
45
- // campaign execution is still guarded at the public experiment-run command (v0.5.2 Batch 3):
46
- // this plugin-level path is exercised by programmatic/test callers only until Batch 4
47
- // implements campaign-accurate reporting.
45
+ // execution stays explicitly gated: the config requires includeRealAgents for a preset, and the
46
+ // public experiment-run command rejects incompatible options before this path is reached.
48
47
  const preset = context.config.campaignPreset ? getWarmIndexCampaignPreset(context.config.campaignPreset) : undefined;
49
48
  const cases = preset
50
49
  ? selectWarmIndexCampaignCases(readCasesInput(context.inputs), preset, context.config)
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Typed agent-success-rate report section. Every value here is copied from the plugin's already-calculated analysis and
3
+ * execution evidence: the report layer rescored nothing, reran no check, reparsed no patch and read no reference patch.
4
+ * It holds no prompt, source-file or patch body and no raw command output.
5
+ */
6
+ export const AGENT_SUCCESS_RATE_REPORT_SCHEMA_VERSION = "my-dev-kit-lab-agent-success-rate-report-v1";
@@ -0,0 +1,255 @@
1
+ import { attemptEvidenceOf } from "../../experiments/plugins/agentSuccessRate/attemptEvidence.js";
2
+ import { AGENT_SUCCESS_RATE_PLUGIN_ID, AGENT_SUCCESS_RATE_REAL_AGENT_EXECUTION_MODE, AGENT_SUCCESS_RATE_TREATMENT_IDS } from "../../experiments/plugins/agentSuccessRate/metadata.js";
3
+ import { AGENT_SUCCESS_RATE_REPORT_SCHEMA_VERSION } from "./agentSuccessRateReportModel.js";
4
+ export const AGENT_SUCCESS_RATE_DETERMINISTIC_STATEMENT = "The fixture validates the patch evaluation pipeline and benchmark corpus. It does not measure a coding agent or the effect of context selection.";
5
+ export const AGENT_SUCCESS_RATE_REAL_AGENT_STATEMENT = "The observed outcomes are a descriptive matched comparison of two source-context treatments under the selected provider.";
6
+ const MAX_TEXT = 300;
7
+ const MAX_CHANGED_FILES = 20;
8
+ const bound = (text) => {
9
+ const normalized = text.replace(/\s+/g, " ").trim();
10
+ return normalized.length > MAX_TEXT ? `${normalized.slice(0, MAX_TEXT)}...` : normalized;
11
+ };
12
+ /** Copies a plugin metric. Availability, value and reason are carried through untouched. */
13
+ function copyMetric(metric, fallbackUnit = "count") {
14
+ if (!metric)
15
+ return { availability: "unavailable", value: null, unit: fallbackUnit, reason: "the measurement was not recorded." };
16
+ return { availability: metric.availability, value: metric.value, unit: metric.unit, reason: metric.reason === null ? null : bound(metric.reason) };
17
+ }
18
+ function copyTotal(total) {
19
+ return {
20
+ basis: total.basis,
21
+ contributingCaseCount: total.contributingCaseCount,
22
+ availableCaseCount: total.availableCaseCount,
23
+ unavailableCaseCount: total.unavailableCaseCount,
24
+ sumOfAvailable: total.sumOfAvailable,
25
+ total: copyMetric(total.total)
26
+ };
27
+ }
28
+ function copyDifference(entry) {
29
+ return {
30
+ id: entry.id,
31
+ basis: entry.basis,
32
+ matchedCaseIds: [...entry.matchedCaseIds],
33
+ rawFullFileMean: copyMetric(entry.rawFullFileMean),
34
+ contextPackMean: copyMetric(entry.contextPackMean),
35
+ meanDifference: copyMetric(entry.meanDifference)
36
+ };
37
+ }
38
+ /**
39
+ * A relative, forward-slash artifact reference with no traversal, drive, scheme or absolute form. Anything else is
40
+ * withheld rather than rendered, so a report can never point outside the experiment output directory.
41
+ */
42
+ export function safeAgentSuccessArtifactReference(reference) {
43
+ if (typeof reference !== "string" || reference.length === 0 || reference.length > 400)
44
+ return null;
45
+ if (reference.includes("\\") || reference.includes("\0") || reference.startsWith("/") || /^[A-Za-z]:/.test(reference) || /^[A-Za-z][A-Za-z0-9+.-]*:/.test(reference))
46
+ return null;
47
+ const segments = reference.split("/");
48
+ if (segments.some((segment) => segment === "" || segment === "." || segment === ".."))
49
+ return null;
50
+ return reference;
51
+ }
52
+ function patchOutcome(evidence) {
53
+ return evidence.patch.outcome ?? (evidence.patch.attempted ? "unrecorded" : "not-attempted");
54
+ }
55
+ function verificationAvailability(evidence) {
56
+ return evidence.postEditVerification !== null ? "available" : "unavailable";
57
+ }
58
+ export function buildAgentSuccessRateReport(run) {
59
+ if (run.pluginId !== AGENT_SUCCESS_RATE_PLUGIN_ID)
60
+ return null;
61
+ const candidate = run;
62
+ const analysis = candidate.analysis;
63
+ const execution = candidate.caseExecutionEvidence;
64
+ if (!analysis || !execution) {
65
+ // A run that failed before analysis exists still gets the generic failure report.
66
+ if (run.status === "failed")
67
+ return null;
68
+ throw new Error("Invalid agent-success-rate report source: execution evidence and analysis are required.");
69
+ }
70
+ const inconsistent = analysis.cases.length !== execution.length ||
71
+ analysis.cases.some((entry, index) => entry.caseId !== execution[index].caseId ||
72
+ entry.treatments.length !== AGENT_SUCCESS_RATE_TREATMENT_IDS.length ||
73
+ entry.treatments.some((treatment, position) => treatment.treatmentId !== AGENT_SUCCESS_RATE_TREATMENT_IDS[position]));
74
+ if (inconsistent) {
75
+ throw new Error("Invalid agent-success-rate report source: execution evidence and analysis are inconsistent.");
76
+ }
77
+ const realMode = analysis.executionMode === AGENT_SUCCESS_RATE_REAL_AGENT_EXECUTION_MODE;
78
+ const metadata = (run.metadata ?? {});
79
+ const repairAttempts = realMode && typeof metadata.repairAttempts === "number" ? metadata.repairAttempts : realMode ? 0 : null;
80
+ const timeoutMs = realMode && typeof metadata.timeoutMs === "number" ? metadata.timeoutMs : null;
81
+ const cases = analysis.cases.map((entry, caseIndex) => {
82
+ const evidence = execution[caseIndex];
83
+ return {
84
+ caseId: entry.caseId,
85
+ caseName: bound(evidence.caseName),
86
+ benchmarkProject: entry.benchmarkProject,
87
+ taskLocality: evidence.taskLocality,
88
+ treatments: entry.treatments.map((treatment, treatmentIndex) => {
89
+ const treatmentEvidence = evidence.treatments[treatmentIndex];
90
+ const repair = treatment.repair;
91
+ const changed = treatmentEvidence.change?.changedFiles.map((file) => file.relativePath).filter((file) => safeAgentSuccessArtifactReference(file) !== null) ?? null;
92
+ const errors = attemptEvidenceOf(treatmentEvidence).flatMap((attempt, index) => attempt.errors.slice(0, 10).map((error) => ({ attemptNumber: index + 1, code: bound(error.code), message: bound(error.message) })));
93
+ return {
94
+ treatmentId: treatment.treatmentId,
95
+ executionStatus: treatment.executionStatus,
96
+ evidenceAvailability: treatment.evidenceAvailability,
97
+ initialTaskSuccess: copyMetric(repair ? repair.initialAttemptTaskSuccess : treatment.metrics.taskSuccess, "boolean"),
98
+ finalTaskSuccess: copyMetric(treatment.metrics.taskSuccess, "boolean"),
99
+ attemptCount: repair ? repair.attemptCount : 1,
100
+ repairAttemptCount: repair ? repair.repairAttemptCount : 0,
101
+ repairSucceeded: repair
102
+ ? copyMetric(repair.repairSucceeded, "boolean")
103
+ : { availability: "not-applicable", value: null, unit: "boolean", reason: "deterministic-fixture mode has no repair." },
104
+ taskCheckPassRate: copyMetric(treatment.metrics.taskCheckPassRate, "ratio"),
105
+ regressionCheckPassRate: copyMetric(treatment.metrics.regressionCheckPassRate, "ratio"),
106
+ requiredFactCoverage: copyMetric(treatment.metrics.requiredFactCoverage, "ratio"),
107
+ expectedEditCoverage: copyMetric(treatment.metrics.expectedEditCoverage, "ratio"),
108
+ editScopePrecision: copyMetric(treatment.metrics.editScopePrecision, "ratio"),
109
+ unexpectedChangedFiles: copyMetric(treatment.metrics.unexpectedChangedFileCount, "count"),
110
+ protectedMutations: copyMetric(treatment.metrics.protectedMutationCount, "count"),
111
+ changedFileCount: copyMetric(treatment.metrics.changedFileCount, "count"),
112
+ changedFiles: changed === null || treatment.metrics.changedFileCount.availability !== "available"
113
+ ? null
114
+ : { items: changed.slice(0, MAX_CHANGED_FILES), totalCount: changed.length, omittedCount: Math.max(0, changed.length - MAX_CHANGED_FILES) },
115
+ totalChurn: copyMetric(treatment.metrics.totalChurn, "lines"),
116
+ relativeChurn: copyMetric(treatment.metrics.relativeChurn, "ratio"),
117
+ finalAttemptProviderDurationMs: copyMetric(treatment.metrics.agentDurationMs, "ms"),
118
+ finalAttemptProviderTokens: copyMetric(treatment.metrics.agentTotalTokens, "tokens"),
119
+ totalProviderDurationMs: repair ? copyMetric(repair.totalProviderDurationMs, "ms") : null,
120
+ totalProviderTokens: repair ? copyMetric(repair.totalProviderTokens, "tokens") : null,
121
+ errors: errors.slice(0, 20)
122
+ };
123
+ })
124
+ };
125
+ });
126
+ const treatments = analysis.aggregates.map((aggregate) => {
127
+ const repair = aggregate.repair;
128
+ return {
129
+ treatmentId: aggregate.treatmentId,
130
+ evaluableCases: repair ? repair.finalEvaluableCount : aggregate.evaluableCaseCount,
131
+ initialSuccessfulCases: repair ? repair.initialAttemptSuccessfulCount : aggregate.successfulCaseCount,
132
+ initialSuccessRate: copyMetric(aggregate.initialAttemptSuccessRate, "ratio"),
133
+ finalSuccessfulCases: repair ? repair.finalSuccessfulCount : aggregate.successfulCaseCount,
134
+ finalSuccessRate: copyMetric(repair ? repair.finalTaskSuccessRate : aggregate.taskSuccessRate, "ratio"),
135
+ repair: repair
136
+ ? {
137
+ repairEligibleCases: repair.repairEligibleCaseCount,
138
+ repairAttemptedCases: repair.repairAttemptedCaseCount,
139
+ repairAttempts: repair.totalRepairAttemptCount,
140
+ repairedCases: repair.repairedCaseCount,
141
+ repairSuccessRate: copyMetric(repair.repairSuccessRate, "ratio"),
142
+ meanAttemptsPerEvaluableCase: copyMetric(repair.meanAttemptsPerEvaluableCase, "count"),
143
+ providerDurationMs: repair.providerDurationMs.map(copyTotal),
144
+ providerTokens: repair.providerTokens.map(copyTotal)
145
+ }
146
+ : null
147
+ };
148
+ });
149
+ const repairHistory = realMode
150
+ ? analysis.cases.flatMap((entry, caseIndex) => entry.treatments.flatMap((treatment, treatmentIndex) => {
151
+ const repair = treatment.repair;
152
+ const evidence = execution[caseIndex].treatments[treatmentIndex];
153
+ if (!repair || !evidence.attempts)
154
+ return [];
155
+ return [
156
+ {
157
+ caseId: entry.caseId,
158
+ treatmentId: treatment.treatmentId,
159
+ attempts: repair.attempts.map((attempt, index) => {
160
+ const attemptEvidence = evidence.attempts[index];
161
+ const inner = attemptEvidence.evidence;
162
+ return {
163
+ attemptNumber: attempt.attemptNumber,
164
+ providerStatus: attempt.providerStatus,
165
+ patchOutcome: patchOutcome(inner),
166
+ verificationAvailability: verificationAvailability(inner),
167
+ taskSuccess: copyMetric(attempt.metrics.taskSuccess, "boolean"),
168
+ failureCategory: attempt.failureCategory,
169
+ repairEligible: attempt.repairEligible,
170
+ providerDurationMs: copyMetric(attempt.metrics.agentDurationMs, "ms"),
171
+ providerTokens: copyMetric(attempt.metrics.agentTotalTokens, "tokens"),
172
+ tokenAvailability: attempt.metrics.agentTotalTokens.availability === "available" ? "available" : "unavailable",
173
+ proposedPatchPath: safeAgentSuccessArtifactReference(inner.proposedPatchPath),
174
+ appliedPatchPath: safeAgentSuccessArtifactReference(inner.appliedPatchPath),
175
+ agentArtifactDirectory: safeAgentSuccessArtifactReference(inner.realAgent?.agentArtifactDirectory ?? null)
176
+ };
177
+ })
178
+ }
179
+ ];
180
+ }))
181
+ : [];
182
+ const outcomeAvailability = analysis.cases.flatMap((entry) => entry.treatments.map((treatment) => treatment.metrics.taskSuccess.availability));
183
+ const evaluable = outcomeAvailability.filter((availability) => availability === "available").length;
184
+ const total = outcomeAvailability.length;
185
+ const unavailable = total - evaluable;
186
+ const notes = [];
187
+ if (unavailable > 0)
188
+ notes.push(`${unavailable} of ${total} treatment outcome(s) have no determinate task-success verdict; they are excluded from rates and never counted as failures.`);
189
+ if (realMode && analysis.comparison && analysis.comparison.incompleteCases.length > 0) {
190
+ notes.push(`${analysis.comparison.incompleteCases.length} case(s) are excluded from matched comparisons because a treatment verdict is unavailable.`);
191
+ }
192
+ const comparison = analysis.comparison
193
+ ? (() => {
194
+ const repairComparison = analysis.repairComparison;
195
+ const finalMatched = analysis.comparison.matchedCaseIds.length;
196
+ const evaluableComparison = repairComparison ? repairComparison.interpretation.evaluable : finalMatched > 0;
197
+ const finalPairs = analysis.comparison.pairedOutcomes;
198
+ const differs = finalPairs.onlyRawFullFileSucceeded + finalPairs.onlyContextPackSucceeded > 0;
199
+ return {
200
+ comparisonEvaluable: evaluableComparison,
201
+ observedOutcomeDifference: repairComparison ? repairComparison.interpretation.observedOutcomeDifference : !evaluableComparison ? "not-evaluable" : differs ? "observed" : "not-observed",
202
+ statisticalEffect: "not-assessed",
203
+ finalMatchedCaseIds: [...analysis.comparison.matchedCaseIds],
204
+ finalIncompleteCases: analysis.comparison.incompleteCases.map((entry) => ({ caseId: entry.caseId, unavailableTreatmentIds: [...entry.unavailableTreatmentIds] })),
205
+ finalPairedOutcomes: { ...finalPairs },
206
+ initialMatchedCaseIds: repairComparison ? [...repairComparison.initialAttempt.matchedCaseIds] : null,
207
+ initialIncompleteCases: repairComparison ? repairComparison.initialAttempt.incompleteCases.map((entry) => ({ caseId: entry.caseId, unavailableTreatmentIds: [...entry.unavailableTreatmentIds] })) : null,
208
+ initialPairedOutcomes: repairComparison ? { ...repairComparison.initialAttempt.pairedOutcomes } : null,
209
+ pairedDifferences: repairComparison ? repairComparison.pairedDifferences.map(copyDifference) : []
210
+ };
211
+ })()
212
+ : null;
213
+ const overall = total === 0 || evaluable === 0 ? "unavailable" : unavailable === 0 ? "complete" : "partial";
214
+ return {
215
+ schemaVersion: AGENT_SUCCESS_RATE_REPORT_SCHEMA_VERSION,
216
+ identity: {
217
+ runId: run.runId,
218
+ pluginId: run.pluginId,
219
+ pluginSchemaVersion: "1.0.0",
220
+ runStatus: run.status,
221
+ executionMode: analysis.executionMode,
222
+ providerId: typeof metadata.providerId === "string" ? metadata.providerId : null,
223
+ timeoutMs,
224
+ repairAttempts,
225
+ maxAttemptsPerTreatment: repairAttempts === null ? 1 : 1 + repairAttempts,
226
+ treatmentOrder: [...analysis.treatmentOrder],
227
+ caseCount: analysis.caseCount,
228
+ treatmentOutcomeCount: total
229
+ },
230
+ scientificStatement: realMode ? AGENT_SUCCESS_RATE_REAL_AGENT_STATEMENT : AGENT_SUCCESS_RATE_DETERMINISTIC_STATEMENT,
231
+ limitations: [
232
+ ...analysis.limitations.map(bound),
233
+ ...(realMode
234
+ ? [
235
+ "The corpus is finite and a single run supports no generalization.",
236
+ "Provider output can vary between runs, and provider usage or availability can differ between treatments.",
237
+ "No causal or statistical-significance claim is made; no weighted composite score and no automatic best treatment exist."
238
+ ]
239
+ : [])
240
+ ],
241
+ resultAvailability: { overall, evaluableTreatmentOutcomes: evaluable, unavailableTreatmentOutcomes: unavailable, totalTreatmentOutcomes: total, notes },
242
+ treatments,
243
+ comparison,
244
+ cases,
245
+ repairHistory,
246
+ warnings: run.warnings.map((warning) => ({ code: bound(warning.code), message: bound(warning.message) })),
247
+ artifacts: run.artifacts.map((artifact) => ({
248
+ id: bound(artifact.id),
249
+ label: bound(artifact.label),
250
+ path: safeAgentSuccessArtifactReference(artifact.path),
251
+ caseId: artifact.caseId ?? null,
252
+ variantId: artifact.variantId ?? null
253
+ }))
254
+ };
255
+ }
@@ -0,0 +1,171 @@
1
+ import path from "node:path";
2
+ import { CONTEXT_PACK_GENERATION_METHODOLOGY } from "../../experiments/plugins/contextPackGeneration/analysisArtifact.js";
3
+ import { CONTEXT_PACK_GENERATION_PLUGIN_ID, CONTEXT_PACK_GENERATION_TREATMENT_IDS } from "../../experiments/plugins/contextPackGeneration/metadata.js";
4
+ import { CONTEXT_PACK_GENERATION_REPORT_SCHEMA_VERSION, PACK_PREVIEW_MAX_CALL_RELATIONSHIPS, PACK_PREVIEW_MAX_EVIDENCE_NOTES, PACK_PREVIEW_MAX_FILES, PACK_PREVIEW_MAX_SOURCE_LINES_PER_SLICE, PACK_PREVIEW_MAX_SOURCE_SLICES, PACK_PREVIEW_MAX_SYMBOLS, PACK_PREVIEW_MAX_TESTS } from "./contextPackGenerationReportModel.js";
5
+ /** Fixed wording: observed evidence only. */
6
+ export const CONTEXT_PACK_GENERATION_LIMITATIONS = [
7
+ "This is a context-pack experiment over deterministic my-dev-kit workflows; it is not a coding-agent success evaluation.",
8
+ "Estimated tokens come from the existing Lab estimator over rendered text, not provider billing telemetry.",
9
+ "Unavailable and not-applicable values are not converted to zero.",
10
+ "Scope means use matched complete cases only and are unweighted macro means over task instances.",
11
+ "No composite score, ranking, or winning treatment is produced; treatments are reported side by side.",
12
+ "Tests and call relationships in the pack are descriptive and are not scored.",
13
+ "The context pack is an experimental Lab artifact, not the production my-dev-kit context API.",
14
+ "The pack preview is bounded for display only and does not change the stored pack or any measured size."
15
+ ];
16
+ const copyMetric = (metric) => ({
17
+ availability: metric.availability,
18
+ numerator: metric.numerator,
19
+ denominator: metric.denominator,
20
+ value: metric.value,
21
+ reason: metric.reason
22
+ });
23
+ const NO_MEASUREMENT = { availability: "unavailable", numerator: null, denominator: null, value: null, reason: "no-retrieval-measurement" };
24
+ function bounded(source, limit, project) {
25
+ return { items: source.slice(0, limit).map(project), totalCount: source.length, omittedCount: Math.max(0, source.length - limit) };
26
+ }
27
+ /** Display truncation of a stored slice: first lines only. The pack's own `truncated` flag is copied untouched. */
28
+ function previewSlice(slice) {
29
+ const lines = slice.text.split("\n");
30
+ const shown = lines.slice(0, PACK_PREVIEW_MAX_SOURCE_LINES_PER_SLICE);
31
+ return {
32
+ file: slice.file,
33
+ symbolName: slice.symbolName,
34
+ startLine: slice.startLine,
35
+ endLine: slice.endLine,
36
+ lineCount: slice.lineCount,
37
+ boundaryKnown: slice.boundaryKnown,
38
+ truncated: slice.truncated,
39
+ previewText: shown.join("\n"),
40
+ previewLineCount: shown.length,
41
+ previewTruncated: lines.length > shown.length
42
+ };
43
+ }
44
+ /** External-local evidence carries a redaction marker and no pack body; the preview is counts and availability only. */
45
+ function buildRedactedPreview(entry, redaction) {
46
+ const packTreatment = entry.treatments.find((treatment) => treatment.treatmentId === "context-pack");
47
+ return {
48
+ caseId: entry.caseId,
49
+ status: "redacted-external-local",
50
+ packArtifactPath: null,
51
+ packAvailability: packTreatment?.availability ?? null,
52
+ sections: (packTreatment?.sections ?? []).map((section) => ({
53
+ id: section.id,
54
+ availability: section.availability,
55
+ reason: section.reason,
56
+ itemCount: section.itemCount,
57
+ estimatedTokens: section.estimatedTokens,
58
+ truncatedCount: section.truncatedCount ?? null
59
+ })),
60
+ task: null,
61
+ files: null,
62
+ symbols: null,
63
+ sourceSlices: null,
64
+ callRelationships: null,
65
+ tests: null,
66
+ evidenceNotes: null,
67
+ redaction: { ...redaction }
68
+ };
69
+ }
70
+ function buildPreview(entry, pack) {
71
+ if (entry.identityRedaction)
72
+ return buildRedactedPreview(entry, entry.identityRedaction);
73
+ const packTreatment = entry.treatments.find((treatment) => treatment.treatmentId === "context-pack");
74
+ const packArtifactPath = packTreatment?.packArtifactPath ?? null;
75
+ const base = {
76
+ caseId: entry.caseId,
77
+ packArtifactPath,
78
+ // Section summaries are persisted execution evidence; they never come from the preview truncation.
79
+ sections: (packTreatment?.sections ?? []).map((section) => ({
80
+ id: section.id,
81
+ availability: section.availability,
82
+ reason: section.reason,
83
+ itemCount: section.itemCount,
84
+ estimatedTokens: section.estimatedTokens
85
+ }))
86
+ };
87
+ if (!pack) {
88
+ return {
89
+ ...base,
90
+ status: packArtifactPath === null ? "no-pack-produced" : "pack-artifact-unavailable",
91
+ packAvailability: packTreatment?.availability ?? null,
92
+ task: null,
93
+ files: null,
94
+ symbols: null,
95
+ sourceSlices: null,
96
+ callRelationships: null,
97
+ tests: null,
98
+ evidenceNotes: null
99
+ };
100
+ }
101
+ return {
102
+ ...base,
103
+ status: "available",
104
+ packAvailability: pack.availability,
105
+ task: { title: pack.task.title, summary: pack.task.summary },
106
+ files: bounded(pack.files, PACK_PREVIEW_MAX_FILES, (file) => ({ path: file.path, rank: file.rank, reason: file.reason })),
107
+ symbols: bounded(pack.symbols, PACK_PREVIEW_MAX_SYMBOLS, (symbol) => ({ name: symbol.name, file: symbol.file, line: symbol.line, nodeId: symbol.nodeId })),
108
+ sourceSlices: bounded(pack.sourceSlices, PACK_PREVIEW_MAX_SOURCE_SLICES, previewSlice),
109
+ callRelationships: bounded(pack.callRelationships.filter((relationship) => relationship.kind === "calls"), PACK_PREVIEW_MAX_CALL_RELATIONSHIPS, (relationship) => ({ fromNodeId: relationship.fromNodeId, toNodeId: relationship.toNodeId })),
110
+ tests: bounded(pack.tests, PACK_PREVIEW_MAX_TESTS, (test) => ({ path: test.path, how: test.how })),
111
+ evidenceNotes: bounded(pack.evidenceNotes, PACK_PREVIEW_MAX_EVIDENCE_NOTES, (code) => code)
112
+ };
113
+ }
114
+ /**
115
+ * Presentation-only adapter over the already-calculated `run.analysis` and `run.caseExecutionEvidence`. It recalculates no
116
+ * F1, fact coverage, token size, saving, matched-case membership, mean or delta; it copies persisted values. `contextPacks`
117
+ * are the persisted per-case pack artifacts, loaded by the caller; only display truncation is derived from them.
118
+ */
119
+ export function buildContextPackGenerationReport(run, contextPacks = new Map()) {
120
+ if (run.pluginId !== CONTEXT_PACK_GENERATION_PLUGIN_ID)
121
+ return null;
122
+ const candidate = run;
123
+ const analysis = candidate.analysis;
124
+ const execution = candidate.caseExecutionEvidence;
125
+ if (!analysis || !execution) {
126
+ // A run that failed before analysis exists still gets the generic failure report.
127
+ if (run.status === "failed")
128
+ return null;
129
+ throw new Error("Invalid context-pack-generation report source: execution evidence and analysis are required.");
130
+ }
131
+ const inconsistent = analysis.cases.length !== execution.length ||
132
+ analysis.cases.some((entry, index) => entry.caseId !== execution[index].caseId ||
133
+ entry.treatments.length !== CONTEXT_PACK_GENERATION_TREATMENT_IDS.length ||
134
+ entry.treatments.some((treatment, position) => treatment.treatmentId !== CONTEXT_PACK_GENERATION_TREATMENT_IDS[position]));
135
+ if (inconsistent) {
136
+ throw new Error("Invalid context-pack-generation report source: execution evidence and analysis are inconsistent.");
137
+ }
138
+ const cases = analysis.cases.map((entry, caseIndex) => ({
139
+ caseId: entry.caseId,
140
+ caseName: execution[caseIndex].caseName,
141
+ benchmarkProject: entry.benchmarkProject,
142
+ taskLocality: entry.taskLocality,
143
+ treatments: entry.treatments.map((treatment) => ({
144
+ treatmentId: treatment.treatmentId,
145
+ executionStatus: treatment.executionStatus,
146
+ availability: treatment.availability,
147
+ fileF1: copyMetric(treatment.fileF1),
148
+ symbolF1: copyMetric(treatment.symbolF1),
149
+ factCoverage: treatment.quality ? copyMetric(treatment.quality.fact.coverage) : { ...NO_MEASUREMENT },
150
+ estimatedTokens: treatment.estimatedTokens,
151
+ tokenCountMethod: treatment.tokenCountMethod
152
+ })),
153
+ comparison: { ...entry.comparison }
154
+ }));
155
+ return {
156
+ schemaVersion: CONTEXT_PACK_GENERATION_REPORT_SCHEMA_VERSION,
157
+ experiment: { pluginId: run.pluginId, target: run.target.isSelf ? "self" : "external target" },
158
+ treatmentOrder: [...CONTEXT_PACK_GENERATION_TREATMENT_IDS],
159
+ methodology: { ...CONTEXT_PACK_GENERATION_METHODOLOGY },
160
+ cases,
161
+ scopes: structuredClone(analysis.scopes),
162
+ previews: execution.map((entry) => buildPreview(entry, contextPacks.get(entry.caseId))),
163
+ // Execution/analysis artifacts live directly in the output root; never expose a machine-local absolute path.
164
+ artifacts: run.artifacts.map((artifact) => ({
165
+ id: artifact.id,
166
+ path: artifact.path ? (path.isAbsolute(artifact.path) ? path.basename(artifact.path) : artifact.path) : null,
167
+ caseId: artifact.caseId ?? null
168
+ })),
169
+ limitations: [...CONTEXT_PACK_GENERATION_LIMITATIONS]
170
+ };
171
+ }
@@ -5,6 +5,8 @@ import { buildIncrementalChangeStalenessPluginReport } from "./buildIncrementalC
5
5
  import { buildContextWindowScalingReport } from "./buildContextWindowScalingReport.js";
6
6
  import { buildRetrievalPrecisionRecallReport } from "./buildRetrievalPrecisionRecallReport.js";
7
7
  import { buildRetrievalQueryStrategyComparisonReport } from "./buildRetrievalQueryStrategyComparisonReport.js";
8
+ import { buildContextPackGenerationReport } from "./buildContextPackGenerationReport.js";
9
+ import { AGENT_SUCCESS_RATE_DETERMINISTIC_STATEMENT, AGENT_SUCCESS_RATE_REAL_AGENT_STATEMENT, buildAgentSuccessRateReport } from "./buildAgentSuccessRateReport.js";
8
10
  // Bulk context-window-scaling evidence is presented by the typed report section; the complete
9
11
  // evidence stays in context-window-scaling-execution.json.
10
12
  const CONTEXT_WINDOW_SCALING_BULK_KEYS = ["executionEvidence", "aggregate"];
@@ -12,6 +14,10 @@ const CONTEXT_WINDOW_SCALING_BULK_KEYS = ["executionEvidence", "aggregate"];
12
14
  const RETRIEVAL_PRECISION_RECALL_BULK_KEYS = ["caseExecutionEvidence", "aggregate"];
13
15
  // Same for retrieval-query-strategy-comparison: the typed section presents execution evidence and analysis.
14
16
  const RETRIEVAL_QUERY_STRATEGY_COMPARISON_BULK_KEYS = ["caseExecutionEvidence", "analysis"];
17
+ // Same for context-pack-generation: the typed section presents execution evidence and analysis.
18
+ const CONTEXT_PACK_GENERATION_BULK_KEYS = ["caseExecutionEvidence", "analysis"];
19
+ // Same for agent-success-rate: the typed section presents execution evidence and analysis.
20
+ const AGENT_SUCCESS_RATE_BULK_KEYS = ["caseExecutionEvidence", "analysis"];
15
21
  const V043_BULK_ARRAY_KEYS = [
16
22
  "v043StageContextExecutions",
17
23
  "v043StageContextEvaluations",
@@ -26,6 +32,8 @@ export function buildPluginExperimentReport(args) {
26
32
  const contextWindowScaling = buildContextWindowScalingReport(args.run);
27
33
  const retrievalPrecisionRecall = buildRetrievalPrecisionRecallReport(args.run);
28
34
  const retrievalQueryStrategyComparison = buildRetrievalQueryStrategyComparisonReport(args.run);
35
+ const contextPackGeneration = buildContextPackGenerationReport(args.run, args.contextPacks);
36
+ const agentSuccessRate = buildAgentSuccessRateReport(args.run);
29
37
  const rawRun = { ...args.run, artifacts: relativizeArtifacts(args.run.artifacts, outputRoot) };
30
38
  for (const key of V043_BULK_ARRAY_KEYS) {
31
39
  delete rawRun[key];
@@ -45,6 +53,16 @@ export function buildPluginExperimentReport(args) {
45
53
  delete rawRun[key];
46
54
  }
47
55
  }
56
+ if (contextPackGeneration) {
57
+ for (const key of CONTEXT_PACK_GENERATION_BULK_KEYS) {
58
+ delete rawRun[key];
59
+ }
60
+ }
61
+ if (agentSuccessRate) {
62
+ for (const key of AGENT_SUCCESS_RATE_BULK_KEYS) {
63
+ delete rawRun[key];
64
+ }
65
+ }
48
66
  return {
49
67
  metadata: {
50
68
  generatedAt: args.generatedAt ?? new Date().toISOString(),
@@ -73,8 +91,10 @@ export function buildPluginExperimentReport(args) {
73
91
  contextWindowScaling,
74
92
  retrievalPrecisionRecall,
75
93
  retrievalQueryStrategyComparison,
94
+ contextPackGeneration,
95
+ agentSuccessRate,
76
96
  contextStrategyComparisonV043,
77
- interpretation: buildInterpretation(args.run, contextStrategyComparisonV043, warmIndexReuse, contextWindowScaling, retrievalPrecisionRecall, retrievalQueryStrategyComparison),
97
+ interpretation: buildInterpretation(args.run, contextStrategyComparisonV043, warmIndexReuse, contextWindowScaling, retrievalPrecisionRecall, retrievalQueryStrategyComparison, contextPackGeneration, agentSuccessRate),
78
98
  rawRun,
79
99
  };
80
100
  }
@@ -153,7 +173,34 @@ function affectedNeighborhoodSentence(report) {
153
173
  `reindex recommendations were recommended=${summary.recommendedReindexCount}, not-indicated=${summary.notIndicatedReindexCount}, unknown=${summary.unknownReindexRecommendationCount}. ` +
154
174
  "Affected-neighborhood evidence uses a one-hop baseline graph around confirmed changed indexed files/symbols. It is observational and does not alter retrieval or execution status.");
155
175
  }
156
- function buildInterpretation(run, contextStrategyComparisonV043, warmIndexReuse, contextWindowScaling, retrievalPrecisionRecall, retrievalQueryStrategyComparison) {
176
+ function buildInterpretation(run, contextStrategyComparisonV043, warmIndexReuse, contextWindowScaling, retrievalPrecisionRecall, retrievalQueryStrategyComparison, contextPackGeneration = null, agentSuccessRate = null) {
177
+ if (agentSuccessRate) {
178
+ const real = agentSuccessRate.identity.executionMode === "real-agent";
179
+ const [raw, pack] = agentSuccessRate.treatments;
180
+ const rate = (treatment, kind) => {
181
+ const metric = kind === "initial" ? treatment?.initialSuccessRate : treatment?.finalSuccessRate;
182
+ return metric && metric.availability === "available" && typeof metric.value === "number" ? metric.value.toFixed(4) : "unavailable";
183
+ };
184
+ const summary = real
185
+ ? `${AGENT_SUCCESS_RATE_REAL_AGENT_STATEMENT} Provider ${agentSuccessRate.identity.providerId ?? "unknown"} ran ${agentSuccessRate.identity.caseCount} case(s) with up to ${agentSuccessRate.identity.maxAttemptsPerTreatment} attempt(s) per treatment. Initial-attempt success rate: raw-full-file ${rate(raw, "initial")}, context-pack ${rate(pack, "initial")}; final success rate: raw-full-file ${rate(raw, "final")}, context-pack ${rate(pack, "final")}. No treatment is declared best and no statistical or causal claim is made.`
186
+ : `${AGENT_SUCCESS_RATE_DETERMINISTIC_STATEMENT} ${agentSuccessRate.identity.caseCount} case(s) were evaluated for each treatment identity.`;
187
+ return {
188
+ summary,
189
+ recommendedNextStep: "Review per-case results, the repair history and the scientific limitations; unavailable evidence is never counted as a failure or as zero."
190
+ };
191
+ }
192
+ if (contextPackGeneration) {
193
+ const overall = contextPackGeneration.scopes.find((scope) => scope.scopeId === "overall");
194
+ const saved = overall?.tokenSavings;
195
+ const deltas = overall?.pairedDeltas;
196
+ const summary = overall && saved && deltas
197
+ ? `Overall matched comparison over ${overall.includedCaseCount} of ${overall.caseCount} case(s): the context pack used a mean of ${saved.meanTokensSaved} fewer estimated tokens than raw full-file context (${saved.percentSavedOfMeans}% of the raw mean; a negative value means more tokens); mean fact coverage delta ${deltas.meanFactCoverageDelta}, mean file F1 delta ${deltas.meanFileF1Delta}, mean symbol F1 delta ${deltas.meanSymbolF1Delta}. The treatments are reported side by side without a composite score.`
198
+ : "No matched complete-case context-pack comparison was available for the overall scope. Review treatment availability and excluded cases before drawing conclusions.";
199
+ return {
200
+ summary,
201
+ recommendedNextStep: "Review per-case coverage and size, the scope aggregates, and the bounded pack preview; unavailable values are never treated as zero."
202
+ };
203
+ }
157
204
  if (retrievalQueryStrategyComparison) {
158
205
  const overall = retrievalQueryStrategyComparison.scopes.find((scope) => scope.scopeId === "overall");
159
206
  const taskTypes = "Task-type results are reported separately for localized, cross-module, and broad-change cases.";
@@ -0,0 +1,9 @@
1
+ export const CONTEXT_PACK_GENERATION_REPORT_SCHEMA_VERSION = "my-dev-kit-lab-context-pack-generation-report-v1";
2
+ /** Report-presentation limits only. They never change the experimental pack limits and are not CLI configuration. */
3
+ export const PACK_PREVIEW_MAX_FILES = 5;
4
+ export const PACK_PREVIEW_MAX_SYMBOLS = 5;
5
+ export const PACK_PREVIEW_MAX_SOURCE_SLICES = 3;
6
+ export const PACK_PREVIEW_MAX_SOURCE_LINES_PER_SLICE = 12;
7
+ export const PACK_PREVIEW_MAX_CALL_RELATIONSHIPS = 5;
8
+ export const PACK_PREVIEW_MAX_TESTS = 5;
9
+ export const PACK_PREVIEW_MAX_EVIDENCE_NOTES = 5;