@dailephd/my-dev-kit-lab 0.8.0 → 0.8.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.
- package/CHANGELOG.md +27 -0
- package/README.md +7 -4
- package/dist/src/cli/help.js +35 -1
- package/dist/src/commands/runExperimentDescribeCommand.js +15 -1
- package/dist/src/commands/runExperimentRunCommand.js +177 -4
- package/dist/src/evaluation/retrievalQuality/metrics.js +27 -2
- package/dist/src/evaluation/retrievalQueryStrategies.js +26 -0
- package/dist/src/evaluation/retrievalQueryStrategyEvidence.js +58 -0
- package/dist/src/evaluation/runMyDevKitRetrieval.js +60 -51
- package/dist/src/evaluation/runSemanticRetrievalStrategy.js +303 -0
- package/dist/src/experiments/defaultRegistry.js +4 -0
- package/dist/src/experiments/plugins/contextPackGeneration/analysis.js +157 -0
- package/dist/src/experiments/plugins/contextPackGeneration/analysisArtifact.js +22 -0
- package/dist/src/experiments/plugins/contextPackGeneration/analysisTypes.js +1 -0
- package/dist/src/experiments/plugins/contextPackGeneration/buildContextPack.js +84 -0
- package/dist/src/experiments/plugins/contextPackGeneration/config.js +39 -0
- package/dist/src/experiments/plugins/contextPackGeneration/execution.js +361 -0
- package/dist/src/experiments/plugins/contextPackGeneration/executionArtifact.js +17 -0
- package/dist/src/experiments/plugins/contextPackGeneration/executionTypes.js +11 -0
- package/dist/src/experiments/plugins/contextPackGeneration/identityEvidence.js +71 -0
- package/dist/src/experiments/plugins/contextPackGeneration/index.js +19 -0
- package/dist/src/experiments/plugins/contextPackGeneration/localSubjectExecution.js +146 -0
- package/dist/src/experiments/plugins/contextPackGeneration/localSubjectPrivacy.js +276 -0
- package/dist/src/experiments/plugins/contextPackGeneration/metadata.js +24 -0
- package/dist/src/experiments/plugins/contextPackGeneration/metrics.js +46 -0
- package/dist/src/experiments/plugins/contextPackGeneration/packArtifact.js +17 -0
- package/dist/src/experiments/plugins/contextPackGeneration/packEvidence.js +152 -0
- package/dist/src/experiments/plugins/contextPackGeneration/packSelectionPolicy.js +305 -0
- package/dist/src/experiments/plugins/contextPackGeneration/plugin.js +355 -0
- package/dist/src/experiments/plugins/contextPackGeneration/renderContextPack.js +61 -0
- package/dist/src/experiments/plugins/contextPackGeneration/types.js +29 -0
- package/dist/src/experiments/plugins/contextWindowScaling/localSubjectPrivacy.js +2 -0
- package/dist/src/experiments/plugins/index.js +1 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/analysis.js +172 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/analysisArtifact.js +28 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/analysisTypes.js +2 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/config.js +39 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/execution.js +225 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/executionArtifact.js +15 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/index.js +12 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/localSubjectExecution.js +124 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/localSubjectPrivacy.js +176 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/metadata.js +51 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/metrics.js +60 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/plugin.js +292 -0
- package/dist/src/experiments/plugins/retrievalQueryStrategyComparison/types.js +1 -0
- package/dist/src/report/experiments/buildContextPackGenerationReport.js +171 -0
- package/dist/src/report/experiments/buildPluginExperimentReport.js +47 -2
- package/dist/src/report/experiments/buildRetrievalQueryStrategyComparisonReport.js +91 -0
- package/dist/src/report/experiments/contextPackGenerationReportModel.js +9 -0
- package/dist/src/report/experiments/index.js +9 -0
- package/dist/src/report/experiments/loadContextPackArtifacts.js +43 -0
- package/dist/src/report/experiments/renderContextPackGenerationHtml.js +122 -0
- package/dist/src/report/experiments/renderContextPackGenerationText.js +101 -0
- package/dist/src/report/experiments/renderPluginExperimentReportHtml.js +6 -0
- package/dist/src/report/experiments/renderPluginExperimentReportText.js +16 -0
- package/dist/src/report/experiments/renderRetrievalQueryStrategyComparisonHtml.js +96 -0
- package/dist/src/report/experiments/renderRetrievalQueryStrategyComparisonText.js +58 -0
- package/dist/src/report/experiments/retrievalQueryStrategyComparisonReportModel.js +1 -0
- package/dist/src/report/experiments/writePluginExperimentReports.js +2 -0
- package/docs/METRICS.md +149 -2
- package/package.json +1 -1
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { resolveWithinRoot } from "../../../core/pathSafety.js";
|
|
4
|
+
import { serializeLocalRepositorySubjectManifest } from "../../../evaluation/localRepositorySubject/index.js";
|
|
5
|
+
import { summarizeExperimentRun } from "../../results.js";
|
|
6
|
+
import { LocalSubjectExecutionError } from "../contextWindowScaling/localSubjectErrors.js";
|
|
7
|
+
import { projectExternalLocalTarget } from "../contextWindowScaling/localSubjectPrivacy.js";
|
|
8
|
+
import { isSamePhysicalDirectory } from "../contextWindowScaling/localSubjectScratch.js";
|
|
9
|
+
import { selectWarmIndexCases } from "../warmIndexReuse/selection.js";
|
|
10
|
+
import { defaultRetrievalQueryStrategyComparisonConfig, retrievalQueryStrategyComparisonConfigDefinition, validateRetrievalQueryStrategyComparisonConfig } from "./config.js";
|
|
11
|
+
import { analyzeRetrievalQueryStrategyComparison } from "./analysis.js";
|
|
12
|
+
import { buildRetrievalQueryStrategyComparisonAnalysisArtifact, RETRIEVAL_QUERY_STRATEGY_COMPARISON_ANALYSIS_ARTIFACT_FILE } from "./analysisArtifact.js";
|
|
13
|
+
import { executeRetrievalQueryStrategyCaseFromPreparedIndex, executeRetrievalQueryStrategyComparison } from "./execution.js";
|
|
14
|
+
import { executeLocalRepositorySubjectRetrievalQueryStrategyComparison } from "./localSubjectExecution.js";
|
|
15
|
+
import { assertRetrievalQueryStrategyExternalProjectionIsPrivate, describeRetrievalQueryStrategyLocalSubjectFailureForPersistence, projectRetrievalQueryStrategyAnalysisForExternalLocalPersistence, projectRetrievalQueryStrategyExecutionForExternalLocalPersistence, RETRIEVAL_QUERY_STRATEGY_UNEXPECTED_EXTERNAL_FAILURE_MESSAGE } from "./localSubjectPrivacy.js";
|
|
16
|
+
import { buildRetrievalQueryStrategyComparisonExecutionArtifact, RETRIEVAL_QUERY_STRATEGY_COMPARISON_EXECUTION_ARTIFACT_FILE } from "./executionArtifact.js";
|
|
17
|
+
import { RETRIEVAL_QUERY_STRATEGY_COMPARISON_PLUGIN_ID, RETRIEVAL_QUERY_STRATEGY_COMPARISON_VARIANTS, retrievalQueryStrategyComparisonMetadata } from "./metadata.js";
|
|
18
|
+
import { toRetrievalQueryStrategyOutcomeMetrics, toRetrievalQueryStrategyRunMetrics } from "./metrics.js";
|
|
19
|
+
/** Privacy-safe subject manifest persisted beside the artifacts for external-local runs (same file as the other local-subject plugins). */
|
|
20
|
+
export const RETRIEVAL_QUERY_STRATEGY_COMPARISON_LOCAL_SUBJECT_MANIFEST_FILE = "local-repository-subject-manifest.json";
|
|
21
|
+
/** An external target must always arrive with a loaded local repository subject; there is no bundled fallback against it. */
|
|
22
|
+
export const RETRIEVAL_QUERY_STRATEGY_COMPARISON_EXTERNAL_REQUIRES_SUBJECT_MESSAGE = "External-local retrieval-query-strategy-comparison targets require a loaded local repository subject (--local-subject-config).";
|
|
23
|
+
export const retrievalQueryStrategyComparisonPlugin = {
|
|
24
|
+
metadata: retrievalQueryStrategyComparisonMetadata,
|
|
25
|
+
defaultConfig: defaultRetrievalQueryStrategyComparisonConfig,
|
|
26
|
+
configDefinition: retrievalQueryStrategyComparisonConfigDefinition,
|
|
27
|
+
supportedVariants: RETRIEVAL_QUERY_STRATEGY_COMPARISON_VARIANTS.map((variant) => variant.id),
|
|
28
|
+
validateConfig: validateRetrievalQueryStrategyComparisonConfig,
|
|
29
|
+
async run(context) {
|
|
30
|
+
const startedAt = context.startedAt.toISOString();
|
|
31
|
+
const localSubject = readLocalSubjectInput(context.inputs);
|
|
32
|
+
if (localSubject)
|
|
33
|
+
return runLocalSubject(context, localSubject, startedAt);
|
|
34
|
+
// The runner does not enforce supportedTargets; never fall back to the bundled corpus against an external repository.
|
|
35
|
+
if (context.target.kind !== "self" || context.target.isSelf !== true) {
|
|
36
|
+
throw new Error(RETRIEVAL_QUERY_STRATEGY_COMPARISON_EXTERNAL_REQUIRES_SUBJECT_MESSAGE);
|
|
37
|
+
}
|
|
38
|
+
const cases = selectWarmIndexCases(readCasesInput(context.inputs), context.config);
|
|
39
|
+
const outDir = context.outputRoot ?? path.resolve(context.toolRoot, context.config.outDir);
|
|
40
|
+
await mkdir(outDir, { recursive: true });
|
|
41
|
+
const caseEvidence = await executeRetrievalQueryStrategyComparison({
|
|
42
|
+
cases,
|
|
43
|
+
kitCommand: context.config.kitCommand,
|
|
44
|
+
outputRoot: outDir,
|
|
45
|
+
dependencies: readDependenciesInput(context.inputs)
|
|
46
|
+
});
|
|
47
|
+
// Scientific analysis is calculated in memory before persistence; reports later consume it, never recalculate it.
|
|
48
|
+
const analysis = analyzeRetrievalQueryStrategyComparison(cases, caseEvidence);
|
|
49
|
+
const completedAt = new Date().toISOString();
|
|
50
|
+
const artifact = buildRetrievalQueryStrategyComparisonExecutionArtifact({
|
|
51
|
+
runId: context.runId,
|
|
52
|
+
pluginId: RETRIEVAL_QUERY_STRATEGY_COMPARISON_PLUGIN_ID,
|
|
53
|
+
pluginSchemaVersion: retrievalQueryStrategyComparisonMetadata.schemaVersion,
|
|
54
|
+
startedAt,
|
|
55
|
+
completedAt,
|
|
56
|
+
cases: caseEvidence
|
|
57
|
+
});
|
|
58
|
+
const analysisArtifact = buildRetrievalQueryStrategyComparisonAnalysisArtifact({
|
|
59
|
+
runId: context.runId,
|
|
60
|
+
pluginId: RETRIEVAL_QUERY_STRATEGY_COMPARISON_PLUGIN_ID,
|
|
61
|
+
pluginSchemaVersion: retrievalQueryStrategyComparisonMetadata.schemaVersion,
|
|
62
|
+
startedAt,
|
|
63
|
+
completedAt,
|
|
64
|
+
analysis
|
|
65
|
+
});
|
|
66
|
+
const executionArtifactPath = resolveWithinRoot(outDir, RETRIEVAL_QUERY_STRATEGY_COMPARISON_EXECUTION_ARTIFACT_FILE);
|
|
67
|
+
const analysisArtifactPath = resolveWithinRoot(outDir, RETRIEVAL_QUERY_STRATEGY_COMPARISON_ANALYSIS_ARTIFACT_FILE);
|
|
68
|
+
await writeFile(executionArtifactPath, `${JSON.stringify(artifact, null, 2)}\n`, "utf8");
|
|
69
|
+
await writeFile(analysisArtifactPath, `${JSON.stringify(analysisArtifact, null, 2)}\n`, "utf8");
|
|
70
|
+
return mapRetrievalQueryStrategyComparisonToRun({
|
|
71
|
+
runId: context.runId,
|
|
72
|
+
startedAt,
|
|
73
|
+
completedAt,
|
|
74
|
+
target: context.target,
|
|
75
|
+
caseEvidence,
|
|
76
|
+
analysis,
|
|
77
|
+
executionArtifactPath,
|
|
78
|
+
analysisArtifactPath
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
summarize(result) {
|
|
82
|
+
return result.summary ?? summarizeExperimentRun(result);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
function readLocalSubjectInput(inputs) {
|
|
86
|
+
const value = inputs?.localSubject;
|
|
87
|
+
return value && typeof value === "object" ? value : undefined;
|
|
88
|
+
}
|
|
89
|
+
/** Test seams for the external path derive from the same optional dependency input the bundled path reads. */
|
|
90
|
+
function readLocalSubjectDependencies(inputs) {
|
|
91
|
+
const injected = readDependenciesInput(inputs);
|
|
92
|
+
if (!injected)
|
|
93
|
+
return undefined;
|
|
94
|
+
const { buildIndex, runCoreStrategy, runSemanticStrategy } = injected;
|
|
95
|
+
return {
|
|
96
|
+
...(buildIndex ? { buildIndex } : {}),
|
|
97
|
+
...(runCoreStrategy || runSemanticStrategy
|
|
98
|
+
? {
|
|
99
|
+
executeCase: (options) => executeRetrievalQueryStrategyCaseFromPreparedIndex({
|
|
100
|
+
...options,
|
|
101
|
+
dependencies: { ...(runCoreStrategy ? { runCoreStrategy } : {}), ...(runSemanticStrategy ? { runSemanticStrategy } : {}) }
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
: {})
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* External-local path. The safe seam owns execution, immutability and scratch cleanup and either returns evidence or
|
|
109
|
+
* throws. Scientific analysis is calculated from the real, unprojected identities; only then is the evidence
|
|
110
|
+
* privacy-projected and asserted private. Nothing durable is written before every gate has passed, and then in this
|
|
111
|
+
* order: execution artifact, analysis artifact, manifest.
|
|
112
|
+
*/
|
|
113
|
+
async function runLocalSubject(context, subject, startedAt) {
|
|
114
|
+
if (context.target.isSelf || context.target.kind !== "external-local") {
|
|
115
|
+
throw new Error("Local-repository subject mode requires an external-local target.");
|
|
116
|
+
}
|
|
117
|
+
if (context.config.caseIds !== undefined || context.config.benchmarkProjects !== undefined) {
|
|
118
|
+
throw new Error("Case and benchmark-project filters are not supported for an external local repository subject; the subject config owns the case set.");
|
|
119
|
+
}
|
|
120
|
+
if (!(await isSamePhysicalDirectory(context.target.targetRoot, subject.repositoryRoot))) {
|
|
121
|
+
throw new Error("The selected --target is not the repository the local subject was loaded from.");
|
|
122
|
+
}
|
|
123
|
+
const outDir = context.outputRoot;
|
|
124
|
+
if (!outDir)
|
|
125
|
+
throw new Error("Local-repository subject mode requires an experiment output directory.");
|
|
126
|
+
let localResult;
|
|
127
|
+
try {
|
|
128
|
+
localResult = await executeLocalRepositorySubjectRetrievalQueryStrategyComparison({
|
|
129
|
+
subject,
|
|
130
|
+
kitCommand: context.config.kitCommand,
|
|
131
|
+
workRoot: outDir,
|
|
132
|
+
dependencies: readLocalSubjectDependencies(context.inputs)
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (error instanceof LocalSubjectExecutionError)
|
|
137
|
+
throw new Error(describeRetrievalQueryStrategyLocalSubjectFailureForPersistence(error));
|
|
138
|
+
throw new Error(RETRIEVAL_QUERY_STRATEGY_UNEXPECTED_EXTERNAL_FAILURE_MESSAGE);
|
|
139
|
+
}
|
|
140
|
+
// Science first, on real identities; placeholders are never scientific identities.
|
|
141
|
+
const analysis = analyzeRetrievalQueryStrategyComparison(subject.evaluationCases, localResult.caseEvidence);
|
|
142
|
+
const projectedExecution = projectRetrievalQueryStrategyExecutionForExternalLocalPersistence(localResult.caseEvidence);
|
|
143
|
+
const projectedAnalysis = projectRetrievalQueryStrategyAnalysisForExternalLocalPersistence(analysis);
|
|
144
|
+
const privateValues = {
|
|
145
|
+
filePaths: [...subject.eligibleFiles, ...subject.runtimeSafetyExclusions.gitIgnoredFiles, ...subject.runtimeSafetyExclusions.oversizedFiles],
|
|
146
|
+
caseTitles: subject.evaluationCases.map((evaluationCase) => evaluationCase.title),
|
|
147
|
+
warnings: localResult.caseEvidence.flatMap((entry) => entry.treatments.flatMap((treatment) => treatment.retrieval?.warnings ?? [])),
|
|
148
|
+
privateRoots: [subject.repositoryRoot, outDir]
|
|
149
|
+
};
|
|
150
|
+
assertRetrievalQueryStrategyExternalProjectionIsPrivate(projectedExecution, privateValues);
|
|
151
|
+
assertRetrievalQueryStrategyExternalProjectionIsPrivate(projectedAnalysis, privateValues);
|
|
152
|
+
await mkdir(outDir, { recursive: true });
|
|
153
|
+
const completedAt = new Date().toISOString();
|
|
154
|
+
const executionArtifact = buildRetrievalQueryStrategyComparisonExecutionArtifact({
|
|
155
|
+
runId: context.runId,
|
|
156
|
+
pluginId: RETRIEVAL_QUERY_STRATEGY_COMPARISON_PLUGIN_ID,
|
|
157
|
+
pluginSchemaVersion: retrievalQueryStrategyComparisonMetadata.schemaVersion,
|
|
158
|
+
startedAt,
|
|
159
|
+
completedAt,
|
|
160
|
+
cases: projectedExecution
|
|
161
|
+
});
|
|
162
|
+
const analysisArtifact = buildRetrievalQueryStrategyComparisonAnalysisArtifact({
|
|
163
|
+
runId: context.runId,
|
|
164
|
+
pluginId: RETRIEVAL_QUERY_STRATEGY_COMPARISON_PLUGIN_ID,
|
|
165
|
+
pluginSchemaVersion: retrievalQueryStrategyComparisonMetadata.schemaVersion,
|
|
166
|
+
startedAt,
|
|
167
|
+
completedAt,
|
|
168
|
+
analysis: projectedAnalysis
|
|
169
|
+
});
|
|
170
|
+
await writeFile(resolveWithinRoot(outDir, RETRIEVAL_QUERY_STRATEGY_COMPARISON_EXECUTION_ARTIFACT_FILE), `${JSON.stringify(executionArtifact, null, 2)}\n`, "utf8");
|
|
171
|
+
await writeFile(resolveWithinRoot(outDir, RETRIEVAL_QUERY_STRATEGY_COMPARISON_ANALYSIS_ARTIFACT_FILE), `${JSON.stringify(analysisArtifact, null, 2)}\n`, "utf8");
|
|
172
|
+
await writeFile(resolveWithinRoot(outDir, RETRIEVAL_QUERY_STRATEGY_COMPARISON_LOCAL_SUBJECT_MANIFEST_FILE), serializeLocalRepositorySubjectManifest(subject.manifest), "utf8");
|
|
173
|
+
// Durable external run: logical target and basenames only; metrics come from the unchanged numeric analysis.
|
|
174
|
+
const run = mapRetrievalQueryStrategyComparisonToRun({
|
|
175
|
+
runId: context.runId,
|
|
176
|
+
startedAt,
|
|
177
|
+
completedAt,
|
|
178
|
+
target: projectExternalLocalTarget(subject.manifest),
|
|
179
|
+
caseEvidence: projectedExecution,
|
|
180
|
+
analysis: projectedAnalysis,
|
|
181
|
+
executionArtifactPath: RETRIEVAL_QUERY_STRATEGY_COMPARISON_EXECUTION_ARTIFACT_FILE,
|
|
182
|
+
analysisArtifactPath: RETRIEVAL_QUERY_STRATEGY_COMPARISON_ANALYSIS_ARTIFACT_FILE
|
|
183
|
+
});
|
|
184
|
+
run.artifacts.push({
|
|
185
|
+
id: "local-repository-subject-manifest",
|
|
186
|
+
label: "Privacy-safe local repository subject manifest",
|
|
187
|
+
path: RETRIEVAL_QUERY_STRATEGY_COMPARISON_LOCAL_SUBJECT_MANIFEST_FILE,
|
|
188
|
+
kind: "artifact",
|
|
189
|
+
mimeType: "application/json",
|
|
190
|
+
description: "Privacy-safe logical subject, Git, safety and aggregate inventory metadata without source or private identity lists."
|
|
191
|
+
});
|
|
192
|
+
return run;
|
|
193
|
+
}
|
|
194
|
+
export function mapRetrievalQueryStrategyComparisonToRun(args) {
|
|
195
|
+
const cases = args.caseEvidence.map((entry, caseIndex) => ({
|
|
196
|
+
id: entry.caseId,
|
|
197
|
+
name: entry.caseName,
|
|
198
|
+
outcomes: entry.treatments.map((treatment, treatmentIndex) => buildOutcome(entry, treatment, args.analysis.cases[caseIndex].treatments[treatmentIndex])),
|
|
199
|
+
metadata: { benchmarkProject: entry.benchmarkProject, taskLocality: entry.taskLocality }
|
|
200
|
+
}));
|
|
201
|
+
const run = {
|
|
202
|
+
runId: args.runId,
|
|
203
|
+
pluginId: RETRIEVAL_QUERY_STRATEGY_COMPARISON_PLUGIN_ID,
|
|
204
|
+
startedAt: args.startedAt,
|
|
205
|
+
completedAt: args.completedAt,
|
|
206
|
+
status: aggregateTreatmentStatus(args.caseEvidence.flatMap((entry) => entry.treatments.map((treatment) => treatment.status))),
|
|
207
|
+
target: args.target,
|
|
208
|
+
variants: RETRIEVAL_QUERY_STRATEGY_COMPARISON_VARIANTS.map((variant) => ({ ...variant })),
|
|
209
|
+
cases,
|
|
210
|
+
metrics: toRetrievalQueryStrategyRunMetrics(args.analysis),
|
|
211
|
+
artifacts: [
|
|
212
|
+
{
|
|
213
|
+
id: "retrieval-query-strategy-comparison-execution",
|
|
214
|
+
label: "Retrieval query strategy comparison execution evidence",
|
|
215
|
+
path: args.executionArtifactPath,
|
|
216
|
+
kind: "artifact",
|
|
217
|
+
mimeType: "application/json",
|
|
218
|
+
description: "Matched per-case execution evidence for all seven retrieval query strategies without context text or raw command output."
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
id: "retrieval-query-strategy-comparison-analysis",
|
|
222
|
+
label: "Retrieval query strategy comparison scientific analysis",
|
|
223
|
+
path: args.analysisArtifactPath,
|
|
224
|
+
kind: "artifact",
|
|
225
|
+
mimeType: "application/json",
|
|
226
|
+
description: "Planner-defined retrieval-quality, F1, matched task-type aggregates, and Pareto comparison for the seven retrieval query strategies."
|
|
227
|
+
}
|
|
228
|
+
],
|
|
229
|
+
warnings: [],
|
|
230
|
+
// Outcome failures are the authoritative per-treatment failure location.
|
|
231
|
+
failures: [],
|
|
232
|
+
metadata: { executionArtifactPath: args.executionArtifactPath, analysisArtifactPath: args.analysisArtifactPath },
|
|
233
|
+
caseExecutionEvidence: structuredClone(args.caseEvidence),
|
|
234
|
+
analysis: structuredClone(args.analysis)
|
|
235
|
+
};
|
|
236
|
+
run.summary = summarizeExperimentRun(run);
|
|
237
|
+
return run;
|
|
238
|
+
}
|
|
239
|
+
function buildOutcome(caseEvidence, treatment, treatmentAnalysis) {
|
|
240
|
+
const { caseId, benchmarkProject, taskLocality } = caseEvidence;
|
|
241
|
+
const { strategyId } = treatment;
|
|
242
|
+
return {
|
|
243
|
+
id: `${caseId}:${strategyId}`,
|
|
244
|
+
caseId,
|
|
245
|
+
variantId: strategyId,
|
|
246
|
+
status: treatment.status,
|
|
247
|
+
metrics: toRetrievalQueryStrategyOutcomeMetrics(treatmentAnalysis, caseId),
|
|
248
|
+
artifacts: [],
|
|
249
|
+
warnings: (treatment.retrieval?.warnings ?? []).map((message) => ({
|
|
250
|
+
code: "retrieval-warning",
|
|
251
|
+
message,
|
|
252
|
+
variantId: strategyId,
|
|
253
|
+
caseId
|
|
254
|
+
})),
|
|
255
|
+
failures: treatment.errors.map((error) => ({
|
|
256
|
+
code: error.code,
|
|
257
|
+
message: error.message,
|
|
258
|
+
variantId: strategyId,
|
|
259
|
+
caseId,
|
|
260
|
+
recoverable: true
|
|
261
|
+
})),
|
|
262
|
+
metadata: {
|
|
263
|
+
benchmarkProject,
|
|
264
|
+
taskLocality,
|
|
265
|
+
evidenceAvailability: treatment.retrieval?.evidenceAvailability ?? null
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function aggregateTreatmentStatus(statuses) {
|
|
270
|
+
if (statuses.length === 0)
|
|
271
|
+
return "skipped";
|
|
272
|
+
if (statuses.every((status) => status === "completed"))
|
|
273
|
+
return "completed";
|
|
274
|
+
if (statuses.every((status) => status === "skipped"))
|
|
275
|
+
return "skipped";
|
|
276
|
+
if (statuses.every((status) => status === "failed"))
|
|
277
|
+
return "failed";
|
|
278
|
+
return "partial";
|
|
279
|
+
}
|
|
280
|
+
function readCasesInput(inputs) {
|
|
281
|
+
const value = inputs?.cases;
|
|
282
|
+
if (!Array.isArray(value)) {
|
|
283
|
+
throw new Error("Retrieval query strategy comparison requires cases input.");
|
|
284
|
+
}
|
|
285
|
+
return value;
|
|
286
|
+
}
|
|
287
|
+
function readDependenciesInput(inputs) {
|
|
288
|
+
const value = inputs?.retrievalDependencies;
|
|
289
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
290
|
+
? value
|
|
291
|
+
: undefined;
|
|
292
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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
|
+
}
|
|
@@ -4,11 +4,17 @@ import { buildWarmIndexReuseReport } from "./buildWarmIndexReuseReport.js";
|
|
|
4
4
|
import { buildIncrementalChangeStalenessPluginReport } from "./buildIncrementalChangeStalenessPluginReport.js";
|
|
5
5
|
import { buildContextWindowScalingReport } from "./buildContextWindowScalingReport.js";
|
|
6
6
|
import { buildRetrievalPrecisionRecallReport } from "./buildRetrievalPrecisionRecallReport.js";
|
|
7
|
+
import { buildRetrievalQueryStrategyComparisonReport } from "./buildRetrievalQueryStrategyComparisonReport.js";
|
|
8
|
+
import { buildContextPackGenerationReport } from "./buildContextPackGenerationReport.js";
|
|
7
9
|
// Bulk context-window-scaling evidence is presented by the typed report section; the complete
|
|
8
10
|
// evidence stays in context-window-scaling-execution.json.
|
|
9
11
|
const CONTEXT_WINDOW_SCALING_BULK_KEYS = ["executionEvidence", "aggregate"];
|
|
10
12
|
// Same for retrieval-precision-recall: the typed section presents the evidence; the execution artifact keeps all of it.
|
|
11
13
|
const RETRIEVAL_PRECISION_RECALL_BULK_KEYS = ["caseExecutionEvidence", "aggregate"];
|
|
14
|
+
// Same for retrieval-query-strategy-comparison: the typed section presents execution evidence and analysis.
|
|
15
|
+
const RETRIEVAL_QUERY_STRATEGY_COMPARISON_BULK_KEYS = ["caseExecutionEvidence", "analysis"];
|
|
16
|
+
// Same for context-pack-generation: the typed section presents execution evidence and analysis.
|
|
17
|
+
const CONTEXT_PACK_GENERATION_BULK_KEYS = ["caseExecutionEvidence", "analysis"];
|
|
12
18
|
const V043_BULK_ARRAY_KEYS = [
|
|
13
19
|
"v043StageContextExecutions",
|
|
14
20
|
"v043StageContextEvaluations",
|
|
@@ -22,6 +28,8 @@ export function buildPluginExperimentReport(args) {
|
|
|
22
28
|
const incrementalChangeStaleness = buildIncrementalChangeStalenessPluginReport(args.run);
|
|
23
29
|
const contextWindowScaling = buildContextWindowScalingReport(args.run);
|
|
24
30
|
const retrievalPrecisionRecall = buildRetrievalPrecisionRecallReport(args.run);
|
|
31
|
+
const retrievalQueryStrategyComparison = buildRetrievalQueryStrategyComparisonReport(args.run);
|
|
32
|
+
const contextPackGeneration = buildContextPackGenerationReport(args.run, args.contextPacks);
|
|
25
33
|
const rawRun = { ...args.run, artifacts: relativizeArtifacts(args.run.artifacts, outputRoot) };
|
|
26
34
|
for (const key of V043_BULK_ARRAY_KEYS) {
|
|
27
35
|
delete rawRun[key];
|
|
@@ -36,6 +44,16 @@ export function buildPluginExperimentReport(args) {
|
|
|
36
44
|
delete rawRun[key];
|
|
37
45
|
}
|
|
38
46
|
}
|
|
47
|
+
if (retrievalQueryStrategyComparison) {
|
|
48
|
+
for (const key of RETRIEVAL_QUERY_STRATEGY_COMPARISON_BULK_KEYS) {
|
|
49
|
+
delete rawRun[key];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (contextPackGeneration) {
|
|
53
|
+
for (const key of CONTEXT_PACK_GENERATION_BULK_KEYS) {
|
|
54
|
+
delete rawRun[key];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
39
57
|
return {
|
|
40
58
|
metadata: {
|
|
41
59
|
generatedAt: args.generatedAt ?? new Date().toISOString(),
|
|
@@ -63,8 +81,10 @@ export function buildPluginExperimentReport(args) {
|
|
|
63
81
|
incrementalChangeStaleness,
|
|
64
82
|
contextWindowScaling,
|
|
65
83
|
retrievalPrecisionRecall,
|
|
84
|
+
retrievalQueryStrategyComparison,
|
|
85
|
+
contextPackGeneration,
|
|
66
86
|
contextStrategyComparisonV043,
|
|
67
|
-
interpretation: buildInterpretation(args.run, contextStrategyComparisonV043, warmIndexReuse, contextWindowScaling, retrievalPrecisionRecall),
|
|
87
|
+
interpretation: buildInterpretation(args.run, contextStrategyComparisonV043, warmIndexReuse, contextWindowScaling, retrievalPrecisionRecall, retrievalQueryStrategyComparison, contextPackGeneration),
|
|
68
88
|
rawRun,
|
|
69
89
|
};
|
|
70
90
|
}
|
|
@@ -143,7 +163,32 @@ function affectedNeighborhoodSentence(report) {
|
|
|
143
163
|
`reindex recommendations were recommended=${summary.recommendedReindexCount}, not-indicated=${summary.notIndicatedReindexCount}, unknown=${summary.unknownReindexRecommendationCount}. ` +
|
|
144
164
|
"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.");
|
|
145
165
|
}
|
|
146
|
-
function buildInterpretation(run, contextStrategyComparisonV043, warmIndexReuse, contextWindowScaling, retrievalPrecisionRecall) {
|
|
166
|
+
function buildInterpretation(run, contextStrategyComparisonV043, warmIndexReuse, contextWindowScaling, retrievalPrecisionRecall, retrievalQueryStrategyComparison, contextPackGeneration = null) {
|
|
167
|
+
if (contextPackGeneration) {
|
|
168
|
+
const overall = contextPackGeneration.scopes.find((scope) => scope.scopeId === "overall");
|
|
169
|
+
const saved = overall?.tokenSavings;
|
|
170
|
+
const deltas = overall?.pairedDeltas;
|
|
171
|
+
const summary = overall && saved && deltas
|
|
172
|
+
? `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.`
|
|
173
|
+
: "No matched complete-case context-pack comparison was available for the overall scope. Review treatment availability and excluded cases before drawing conclusions.";
|
|
174
|
+
return {
|
|
175
|
+
summary,
|
|
176
|
+
recommendedNextStep: "Review per-case coverage and size, the scope aggregates, and the bounded pack preview; unavailable values are never treated as zero."
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
if (retrievalQueryStrategyComparison) {
|
|
180
|
+
const overall = retrievalQueryStrategyComparison.scopes.find((scope) => scope.scopeId === "overall");
|
|
181
|
+
const taskTypes = "Task-type results are reported separately for localized, cross-module, and broad-change cases.";
|
|
182
|
+
const summary = overall?.interpretation === "unique-best"
|
|
183
|
+
? `Overall matched comparison: ${overall.bestStrategyId} is the unique nondominated strategy across ${overall.comparisonCaseCount} matched case(s). ${taskTypes}`
|
|
184
|
+
: overall?.interpretation === "tradeoff"
|
|
185
|
+
? `Overall matched comparison has no single best strategy across ${overall.comparisonCaseCount} matched case(s); the Pareto front is ${overall.paretoFrontStrategyIds.join(", ")}. ${taskTypes}`
|
|
186
|
+
: "No matched complete-case retrieval-strategy comparison was available for the overall scope. Review treatment availability and excluded cases before drawing conclusions.";
|
|
187
|
+
return {
|
|
188
|
+
summary,
|
|
189
|
+
recommendedNextStep: "Review the task-type scope table, Pareto fronts, and per-case treatment metrics; do not treat Pareto-front order as a ranking."
|
|
190
|
+
};
|
|
191
|
+
}
|
|
147
192
|
if (retrievalPrecisionRecall) {
|
|
148
193
|
const summary = retrievalPrecisionRecall.runSummary;
|
|
149
194
|
return {
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { RETRIEVAL_QUERY_STRATEGY_IDS } from "../../evaluation/retrievalQueryStrategies.js";
|
|
2
|
+
import { RETRIEVAL_QUERY_STRATEGY_COMPARISON_METHODOLOGY } from "../../experiments/plugins/retrievalQueryStrategyComparison/analysisArtifact.js";
|
|
3
|
+
import { RETRIEVAL_QUERY_STRATEGY_COMPARISON_PLUGIN_ID } from "../../experiments/plugins/retrievalQueryStrategyComparison/metadata.js";
|
|
4
|
+
import { RETRIEVAL_QUERY_STRATEGY_COMPARISON_REPORT_SCHEMA_VERSION } from "./retrievalQueryStrategyComparisonReportModel.js";
|
|
5
|
+
/** Fixed wording: observed evidence only. It never claims a strategy is generally superior. */
|
|
6
|
+
export const RETRIEVAL_QUERY_STRATEGY_COMPARISON_LIMITATIONS = [
|
|
7
|
+
"Retrieval treatments are deterministic my-dev-kit workflows; no coding agent or learned judge participates.",
|
|
8
|
+
"File and symbol precision and recall retain the v0.8.0 set-based identity semantics.",
|
|
9
|
+
"Balanced file and symbol F1 use 2TP / (2TP + FP + FN).",
|
|
10
|
+
"Cross-strategy scope means use matched complete cases only: a task is excluded from every strategy aggregate when any strategy lacks a primary objective.",
|
|
11
|
+
"Scope means are unweighted macro means over task instances.",
|
|
12
|
+
"Pareto dominance compares mean file F1, mean symbol F1, mean fact coverage, and mean retrieved token count without scalar weights.",
|
|
13
|
+
"A unique best strategy is reported only when the Pareto front has exactly one member; multiple nondominated strategies are reported as a tradeoff, not forcibly ranked.",
|
|
14
|
+
"Task-type scopes reuse the existing taskLocality labels: localized, cross-module, and broad-change.",
|
|
15
|
+
"Retrieved token count is a context-size estimate from the selected retrieval payload, not provider billing telemetry.",
|
|
16
|
+
"Unavailable and not-applicable metric values are not converted to zero.",
|
|
17
|
+
"External-local durable reports withhold private file, symbol, fact, semantic-node, warning, and case-title identities."
|
|
18
|
+
];
|
|
19
|
+
const NO_RETRIEVAL_MEASUREMENT = {
|
|
20
|
+
availability: "unavailable",
|
|
21
|
+
numerator: null,
|
|
22
|
+
denominator: null,
|
|
23
|
+
value: null,
|
|
24
|
+
reason: "no-retrieval-measurement"
|
|
25
|
+
};
|
|
26
|
+
const noMeasurement = () => ({ ...NO_RETRIEVAL_MEASUREMENT });
|
|
27
|
+
const copyMetric = (metric) => ({
|
|
28
|
+
availability: metric.availability,
|
|
29
|
+
numerator: metric.numerator,
|
|
30
|
+
denominator: metric.denominator,
|
|
31
|
+
value: metric.value,
|
|
32
|
+
reason: metric.reason
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* Presentation-only adapter over the already-calculated `run.analysis`. It recalculates no precision, recall, F1, fact
|
|
36
|
+
* coverage, mean, Pareto front or best strategy; it only copies values and reads persisted execution status.
|
|
37
|
+
*/
|
|
38
|
+
export function buildRetrievalQueryStrategyComparisonReport(run) {
|
|
39
|
+
if (run.pluginId !== RETRIEVAL_QUERY_STRATEGY_COMPARISON_PLUGIN_ID)
|
|
40
|
+
return null;
|
|
41
|
+
const candidate = run;
|
|
42
|
+
const analysis = candidate.analysis;
|
|
43
|
+
const execution = candidate.caseExecutionEvidence;
|
|
44
|
+
if (!analysis || !execution) {
|
|
45
|
+
// A run that failed before analysis exists still gets the generic failure report.
|
|
46
|
+
if (run.status === "failed")
|
|
47
|
+
return null;
|
|
48
|
+
throw new Error("Invalid retrieval-query-strategy-comparison report source: execution evidence and analysis are required.");
|
|
49
|
+
}
|
|
50
|
+
const inconsistent = analysis.cases.length !== execution.length ||
|
|
51
|
+
analysis.cases.some((entry, index) => entry.caseId !== execution[index].caseId ||
|
|
52
|
+
entry.treatments.length !== RETRIEVAL_QUERY_STRATEGY_IDS.length ||
|
|
53
|
+
entry.treatments.some((treatment, position) => treatment.strategyId !== RETRIEVAL_QUERY_STRATEGY_IDS[position]) ||
|
|
54
|
+
execution[index].treatments.length !== RETRIEVAL_QUERY_STRATEGY_IDS.length);
|
|
55
|
+
if (inconsistent) {
|
|
56
|
+
throw new Error("Invalid retrieval-query-strategy-comparison report source: execution evidence and analysis are inconsistent.");
|
|
57
|
+
}
|
|
58
|
+
const cases = analysis.cases.map((entry, caseIndex) => ({
|
|
59
|
+
caseId: entry.caseId,
|
|
60
|
+
caseName: execution[caseIndex].caseName,
|
|
61
|
+
benchmarkProject: entry.benchmarkProject,
|
|
62
|
+
taskLocality: entry.taskLocality,
|
|
63
|
+
treatments: entry.treatments.map((treatment, position) => {
|
|
64
|
+
const quality = treatment.quality;
|
|
65
|
+
return {
|
|
66
|
+
strategyId: treatment.strategyId,
|
|
67
|
+
executionStatus: treatment.executionStatus,
|
|
68
|
+
evidenceAvailability: execution[caseIndex].treatments[position].retrieval?.evidenceAvailability ?? null,
|
|
69
|
+
filePrecision: quality ? copyMetric(quality.file.precision) : noMeasurement(),
|
|
70
|
+
fileRecall: quality ? copyMetric(quality.file.recall) : noMeasurement(),
|
|
71
|
+
fileF1: copyMetric(treatment.fileF1),
|
|
72
|
+
symbolPrecision: quality ? copyMetric(quality.symbol.precision) : noMeasurement(),
|
|
73
|
+
symbolRecall: quality ? copyMetric(quality.symbol.recall) : noMeasurement(),
|
|
74
|
+
symbolF1: copyMetric(treatment.symbolF1),
|
|
75
|
+
factCoverage: quality ? copyMetric(quality.fact.coverage) : noMeasurement(),
|
|
76
|
+
irrelevantContextRatio: quality ? copyMetric(quality.irrelevantContextRatio) : noMeasurement(),
|
|
77
|
+
retrievedTokenCount: quality?.retrievedTokenCount ?? null,
|
|
78
|
+
tokenCountMethod: quality?.tokenCountMethod ?? null
|
|
79
|
+
};
|
|
80
|
+
})
|
|
81
|
+
}));
|
|
82
|
+
return {
|
|
83
|
+
schemaVersion: RETRIEVAL_QUERY_STRATEGY_COMPARISON_REPORT_SCHEMA_VERSION,
|
|
84
|
+
methodology: structuredClone(RETRIEVAL_QUERY_STRATEGY_COMPARISON_METHODOLOGY),
|
|
85
|
+
strategyOrder: [...RETRIEVAL_QUERY_STRATEGY_IDS],
|
|
86
|
+
identityRedaction: run.target.privacyProjection === "external-local-redacted" ? "external-local-redacted" : null,
|
|
87
|
+
scopes: structuredClone(analysis.scopes),
|
|
88
|
+
cases,
|
|
89
|
+
limitations: [...RETRIEVAL_QUERY_STRATEGY_COMPARISON_LIMITATIONS]
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -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;
|