@dailephd/my-dev-kit-lab 0.4.2 → 0.4.3

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 (92) hide show
  1. package/README.md +23 -113
  2. package/benchmarks/contracts/todo-behavior.md +1 -1
  3. package/benchmarks/projects/task-analytics-large-mixed/README.md +2 -0
  4. package/benchmarks/projects/task-workflow-medium-ts/README.md +3 -1
  5. package/dist/src/evaluation/stageContextDeterminism/calculateStageContextDeterminism.js +52 -0
  6. package/dist/src/evaluation/stageContextDeterminism/canonicalizeStageContextRun.js +53 -0
  7. package/dist/src/evaluation/stageContextDeterminism/index.js +2 -0
  8. package/dist/src/evaluation/stageContextDeterminism/types.js +1 -0
  9. package/dist/src/evaluation/stageContextExpectations/index.js +2 -0
  10. package/dist/src/evaluation/stageContextExpectations/readStageContextExpectationFixtureV1.js +50 -0
  11. package/dist/src/evaluation/stageContextExpectations/readTypes.js +1 -0
  12. package/dist/src/evaluation/stageContextExpectations/types.js +1 -0
  13. package/dist/src/evaluation/stageContextExpectations/validation.js +568 -0
  14. package/dist/src/evaluation/stageContextMetrics/calculateArtifactStateMetrics.js +130 -0
  15. package/dist/src/evaluation/stageContextMetrics/calculateContextSizeMetrics.js +85 -0
  16. package/dist/src/evaluation/stageContextMetrics/calculateExpectationMetrics.js +103 -0
  17. package/dist/src/evaluation/stageContextMetrics/calculateResponsibilityMappingMetrics.js +36 -0
  18. package/dist/src/evaluation/stageContextMetrics/collectContextCapsuleEvidence.js +312 -0
  19. package/dist/src/evaluation/stageContextMetrics/collectRetrievalAuditEvidence.js +35 -0
  20. package/dist/src/evaluation/stageContextMetrics/collectWorkflowInstructionEvidence.js +137 -0
  21. package/dist/src/evaluation/stageContextMetrics/evaluateV043StageContextExecution.js +247 -0
  22. package/dist/src/evaluation/stageContextMetrics/index.js +10 -0
  23. package/dist/src/evaluation/stageContextMetrics/matchStageContextExpectations.js +38 -0
  24. package/dist/src/evaluation/stageContextMetrics/targetKeys.js +35 -0
  25. package/dist/src/evaluation/stageContextMetrics/types.js +1 -0
  26. package/dist/src/evaluation/stageContextSelectors/contextArtifactConsistency.js +79 -0
  27. package/dist/src/evaluation/stageContextSelectors/contextCapsuleSelectors.js +126 -0
  28. package/dist/src/evaluation/stageContextSelectors/index.js +4 -0
  29. package/dist/src/evaluation/stageContextSelectors/retrievalAuditRecordSelectors.js +54 -0
  30. package/dist/src/evaluation/stageContextSelectors/workflowInstructionPacketSelectors.js +51 -0
  31. package/dist/src/evaluation/targetImmutability/captureTargetSnapshot.js +208 -0
  32. package/dist/src/evaluation/targetImmutability/compareTargetSnapshots.js +56 -0
  33. package/dist/src/evaluation/targetImmutability/index.js +3 -0
  34. package/dist/src/evaluation/targetImmutability/types.js +1 -0
  35. package/dist/src/evaluation/targetImmutability/validateTargetImmutabilityConfig.js +130 -0
  36. package/dist/src/evaluation/upstreamArtifacts/artifactReadTypes.js +1 -0
  37. package/dist/src/evaluation/upstreamArtifacts/index.js +3 -0
  38. package/dist/src/evaluation/upstreamArtifacts/jsonTypes.js +1 -0
  39. package/dist/src/evaluation/upstreamArtifacts/myDevKitClassificationTypesV1.js +1 -0
  40. package/dist/src/evaluation/upstreamArtifacts/myDevKitContextArtifactsV1.js +1 -0
  41. package/dist/src/evaluation/upstreamArtifacts/myDevKitSemanticTypesV1.js +1 -0
  42. package/dist/src/evaluation/upstreamArtifacts/orchestratorWorkflowInstructionPacketV1.js +1 -0
  43. package/dist/src/evaluation/upstreamArtifacts/readJsonArtifact.js +53 -0
  44. package/dist/src/evaluation/upstreamArtifacts/readMyDevKitContextCapsuleV1.js +9 -0
  45. package/dist/src/evaluation/upstreamArtifacts/readMyDevKitRetrievalAuditRecordV1.js +9 -0
  46. package/dist/src/evaluation/upstreamArtifacts/readOrchestratorWorkflowInstructionPacketV1.js +9 -0
  47. package/dist/src/evaluation/upstreamArtifacts/runtimeValidation.js +131 -0
  48. package/dist/src/evaluation/upstreamArtifacts/schemaVersion.js +32 -0
  49. package/dist/src/evaluation/upstreamArtifacts/validateMyDevKitContextCapsuleV1.js +1208 -0
  50. package/dist/src/evaluation/upstreamArtifacts/validateMyDevKitRetrievalAuditRecordV1.js +105 -0
  51. package/dist/src/evaluation/upstreamArtifacts/validateOrchestratorWorkflowInstructionPacketV1.js +235 -0
  52. package/dist/src/experiments/plugins/contextStrategyComparison/executeV043StageContextStrategy.js +46 -0
  53. package/dist/src/experiments/plugins/contextStrategyComparison/index.js +9 -0
  54. package/dist/src/experiments/plugins/contextStrategyComparison/loadV043StrategyArtifacts.js +286 -0
  55. package/dist/src/experiments/plugins/contextStrategyComparison/plugin.js +39 -1
  56. package/dist/src/experiments/plugins/contextStrategyComparison/readV043FullWorkflowLibraryFixture.js +162 -0
  57. package/dist/src/experiments/plugins/contextStrategyComparison/resolveV043StrategyInputs.js +43 -0
  58. package/dist/src/experiments/plugins/contextStrategyComparison/resultMapping.js +3 -0
  59. package/dist/src/experiments/plugins/contextStrategyComparison/runV043StageContextStrategyWithAssurance.js +190 -0
  60. package/dist/src/experiments/plugins/contextStrategyComparison/v043FullWorkflowLibraryFixture.js +1 -0
  61. package/dist/src/experiments/plugins/contextStrategyComparison/v043RunAssuranceTypes.js +1 -0
  62. package/dist/src/experiments/plugins/contextStrategyComparison/v043StrategyExecutionTypes.js +1 -0
  63. package/dist/src/experiments/plugins/contextStrategyComparison/v043StrategyIds.js +13 -0
  64. package/dist/src/experiments/plugins/contextStrategyComparison/v043StrategyInputContracts.js +1 -0
  65. package/dist/src/experiments/plugins/contextStrategyComparison/validateV043RunAssuranceConfig.js +59 -0
  66. package/dist/src/experiments/plugins/contextStrategyComparison/validateV043StrategyInput.js +252 -0
  67. package/dist/src/report/experiments/buildContextStrategyComparisonV043Report.js +398 -0
  68. package/dist/src/report/experiments/buildPluginExperimentReport.js +21 -6
  69. package/dist/src/report/experiments/contextStrategyComparisonV043ReportModel.js +1 -0
  70. package/dist/src/report/experiments/index.js +4 -0
  71. package/dist/src/report/experiments/renderContextStrategyComparisonV043Html.js +234 -0
  72. package/dist/src/report/experiments/renderPluginExperimentReportHtml.js +3 -0
  73. package/dist/src/report/experiments/renderPluginExperimentReportText.js +225 -0
  74. package/dist/src/report/experiments/writePluginExperimentReports.js +3 -0
  75. package/dist/src/securityValidation/attackScenarios/scenarios/secretLeakageScenario.js +215 -9
  76. package/docs/METRICS.md +56 -10
  77. package/package.json +1 -1
  78. package/tests/fixtures/full-workflow-library/complete-v1.0.0.json +24 -0
  79. package/tests/fixtures/full-workflow-library/future-minor-v1.1.0-additive.json +25 -0
  80. package/tests/fixtures/stage-context-expectations/complete-v1.0.0.json +230 -0
  81. package/tests/fixtures/stage-context-expectations/future-minor-v1.1.0-additive.json +232 -0
  82. package/tests/fixtures/stage-context-expectations/invalid/malformed-json.txt +1 -0
  83. package/tests/fixtures/stage-context-expectations/invalid/non-object-root.json +1 -0
  84. package/tests/fixtures/stage-context-expectations/minimal-v1.0.0.json +18 -0
  85. package/tests/fixtures/upstream-artifacts/invalid/malformed-json.txt +1 -0
  86. package/tests/fixtures/upstream-artifacts/invalid/non-object-root.json +1 -0
  87. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/context-capsule/complete-v1.0.0.json +504 -0
  88. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/context-capsule/future-minor-v1.1.0-additive.json +955 -0
  89. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/retrieval-audit-record/complete-v1.0.0.json +190 -0
  90. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/retrieval-audit-record/future-minor-v1.1.0-additive.json +327 -0
  91. package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.1/workflow-instruction-packet/complete-v1.0.0.json +160 -0
  92. package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.1/workflow-instruction-packet/future-minor-v1.1.0-additive.json +186 -0
@@ -0,0 +1,398 @@
1
+ import { V043_REPORT_DETAIL_LIMIT, } from "./contextStrategyComparisonV043ReportModel.js";
2
+ const INTERPRETATION_SUMMARY = "Stage-context strategies are reported independently using direct evidence, explicit availability states, target-immutability evidence, and repeated-run determinism. No composite ranking or winning strategy is calculated.";
3
+ const INTERPRETATION_LIMITATIONS = [
4
+ "The published upstream artifacts do not expose considered-but-unselected reads.",
5
+ "The published upstream artifacts do not expose unnecessary-read evidence.",
6
+ "Estimated token counts use ceil(characterCount / 4) per source and are not provider telemetry.",
7
+ "Unavailable and not-applicable values are distinct from zero.",
8
+ ];
9
+ function boundItems(source) {
10
+ const items = source.slice(0, V043_REPORT_DETAIL_LIMIT);
11
+ return {
12
+ totalCount: source.length,
13
+ displayedCount: items.length,
14
+ omittedCount: source.length - items.length,
15
+ items,
16
+ };
17
+ }
18
+ export function buildContextStrategyComparisonV043Report(run) {
19
+ if (run.pluginId !== "context-strategy-comparison")
20
+ return null;
21
+ const candidate = run;
22
+ const executions = candidate.v043StageContextExecutions;
23
+ const evaluations = candidate.v043StageContextEvaluations;
24
+ const assurances = candidate.v043StageContextRunAssurance;
25
+ if (executions === undefined && evaluations === undefined && assurances === undefined) {
26
+ return null;
27
+ }
28
+ if (!Array.isArray(executions) || !Array.isArray(evaluations) || !Array.isArray(assurances)) {
29
+ throw new Error("Invalid v0.4.3 report source: execution, evaluation, and assurance arrays are inconsistent.");
30
+ }
31
+ if (executions.length !== evaluations.length || executions.length !== assurances.length) {
32
+ throw new Error("Invalid v0.4.3 report source: execution, evaluation, and assurance arrays are inconsistent.");
33
+ }
34
+ for (let index = 0; index < executions.length; index += 1) {
35
+ const ids = [
36
+ executions[index].strategyId,
37
+ evaluations[index].strategyId,
38
+ assurances[index].strategyId,
39
+ ].filter((id) => id !== null && id !== undefined);
40
+ const distinct = new Set(ids);
41
+ if (distinct.size > 1) {
42
+ throw new Error("Invalid v0.4.3 report source: execution, evaluation, and assurance arrays are inconsistent.");
43
+ }
44
+ }
45
+ const strategies = executions.map((execution, index) => buildStrategyReport(execution, evaluations[index], assurances[index]));
46
+ return {
47
+ schemaVersion: "1.0.0",
48
+ detailLimit: V043_REPORT_DETAIL_LIMIT,
49
+ summary: buildSummary(executions, evaluations, assurances),
50
+ strategies,
51
+ interpretation: {
52
+ summary: INTERPRETATION_SUMMARY,
53
+ limitations: [...INTERPRETATION_LIMITATIONS],
54
+ },
55
+ };
56
+ }
57
+ function buildSummary(executions, evaluations, assurances) {
58
+ return {
59
+ strategyCount: executions.length,
60
+ completedExecutionCount: executions.filter((e) => e.status === "completed").length,
61
+ invalidInputExecutionCount: executions.filter((e) => e.status === "invalid-input").length,
62
+ failedExecutionCount: executions.filter((e) => e.status === "failed").length,
63
+ completedEvaluationCount: evaluations.filter((e) => e.status === "completed").length,
64
+ notApplicableEvaluationCount: evaluations.filter((e) => e.status === "not-applicable").length,
65
+ failedEvaluationCount: evaluations.filter((e) => e.status === "failed").length,
66
+ passedAssuranceCount: assurances.filter((a) => a.status === "passed").length,
67
+ failedAssuranceCount: assurances.filter((a) => a.status === "failed").length,
68
+ notApplicableAssuranceCount: assurances.filter((a) => a.status === "not-applicable").length,
69
+ };
70
+ }
71
+ function buildStrategyReport(execution, evaluation, assurance) {
72
+ return {
73
+ strategyId: assurance.strategyId,
74
+ artifacts: buildArtifactMetadata(execution),
75
+ execution: buildExecutionSummary(execution),
76
+ evaluation: buildEvaluationSummary(evaluation),
77
+ assurance: buildAssuranceSummary(assurance),
78
+ };
79
+ }
80
+ function buildExecutionSummary(execution) {
81
+ if (execution.status === "completed") {
82
+ return { status: "completed", issues: boundItems([]) };
83
+ }
84
+ const issues = execution.issues.map(buildIssueFromExecutionIssue);
85
+ return { status: execution.status, issues: boundItems(issues) };
86
+ }
87
+ function buildIssueFromExecutionIssue(issue) {
88
+ return {
89
+ code: issue.code,
90
+ fieldPath: issue.fieldPath ?? null,
91
+ message: issue.message,
92
+ runNumber: null,
93
+ };
94
+ }
95
+ function buildArtifactMetadata(execution) {
96
+ if (execution.status !== "completed") {
97
+ return boundItems([]);
98
+ }
99
+ const entries = [];
100
+ entries.push({
101
+ sourceInstance: "expectations",
102
+ artifactKind: "expectation-fixture",
103
+ sourcePath: execution.expectationsSourcePath,
104
+ schemaVersion: execution.expectations.schemaVersion,
105
+ generatedAt: null,
106
+ producerName: null,
107
+ producerVersion: null,
108
+ role: null,
109
+ workflowId: null,
110
+ stageId: null,
111
+ catalogSchemaVersion: null,
112
+ catalogVersion: null,
113
+ fixtureId: null,
114
+ caseId: execution.expectations.caseId,
115
+ title: execution.expectations.title,
116
+ });
117
+ const payload = execution.payload;
118
+ if ("contextArtifacts" in payload) {
119
+ const contextArtifacts = payload.contextArtifacts;
120
+ contextArtifacts.forEach((pair, index) => {
121
+ entries.push(...buildContextArtifactPairMetadata(pair, `contextArtifacts[${index}]`));
122
+ });
123
+ entries.push(buildWorkflowInstructionPacketMetadata(payload.workflowInstructionPacketSourcePath, payload.workflowInstructionPacket));
124
+ }
125
+ else if ("fullWorkflowLibrary" in payload) {
126
+ entries.push(buildFullWorkflowLibraryMetadata(payload.fullWorkflowLibrarySourcePath, payload.fullWorkflowLibrary));
127
+ }
128
+ else if ("workflowInstructionPacket" in payload) {
129
+ entries.push(buildWorkflowInstructionPacketMetadata(payload.workflowInstructionPacketSourcePath, payload.workflowInstructionPacket));
130
+ }
131
+ else if ("testImplementation" in payload) {
132
+ entries.push(...buildContextArtifactPairMetadata(payload.architecture, "architecture"));
133
+ entries.push(...buildContextArtifactPairMetadata(payload.implementation, "implementation"));
134
+ entries.push(...buildContextArtifactPairMetadata(payload.testImplementation, "testImplementation"));
135
+ }
136
+ else if ("implementation" in payload) {
137
+ entries.push(...buildContextArtifactPairMetadata(payload.architecture, "architecture"));
138
+ entries.push(...buildContextArtifactPairMetadata(payload.implementation, "implementation"));
139
+ }
140
+ else if ("architecture" in payload) {
141
+ entries.push(...buildContextArtifactPairMetadata(payload.architecture, "architecture"));
142
+ }
143
+ return boundItems(entries);
144
+ }
145
+ function buildContextArtifactPairMetadata(pair, sourceInstancePrefix) {
146
+ const entries = [
147
+ {
148
+ sourceInstance: `${sourceInstancePrefix}.contextCapsule`,
149
+ artifactKind: "context-capsule",
150
+ sourcePath: pair.contextCapsuleSourcePath,
151
+ schemaVersion: pair.contextCapsule.schemaVersion,
152
+ generatedAt: pair.contextCapsule.generatedAt,
153
+ producerName: pair.contextCapsule.tool.name,
154
+ producerVersion: pair.contextCapsule.tool.version,
155
+ role: pair.contextCapsule.request.role,
156
+ workflowId: null,
157
+ stageId: null,
158
+ catalogSchemaVersion: null,
159
+ catalogVersion: null,
160
+ fixtureId: null,
161
+ caseId: null,
162
+ title: null,
163
+ },
164
+ ];
165
+ if (pair.retrievalAuditRecord) {
166
+ entries.push({
167
+ sourceInstance: `${sourceInstancePrefix}.retrievalAuditRecord`,
168
+ artifactKind: "retrieval-audit-record",
169
+ sourcePath: pair.retrievalAuditRecordSourcePath ?? "",
170
+ schemaVersion: pair.retrievalAuditRecord.schemaVersion,
171
+ generatedAt: pair.retrievalAuditRecord.generatedAt,
172
+ producerName: pair.retrievalAuditRecord.tool.name,
173
+ producerVersion: pair.retrievalAuditRecord.tool.version,
174
+ role: pair.retrievalAuditRecord.request.role,
175
+ workflowId: null,
176
+ stageId: null,
177
+ catalogSchemaVersion: null,
178
+ catalogVersion: null,
179
+ fixtureId: null,
180
+ caseId: null,
181
+ title: null,
182
+ });
183
+ }
184
+ return entries;
185
+ }
186
+ function buildWorkflowInstructionPacketMetadata(sourcePath, packet) {
187
+ return {
188
+ sourceInstance: "workflowInstructionPacket",
189
+ artifactKind: "workflow-instruction-packet",
190
+ sourcePath,
191
+ schemaVersion: packet.schemaVersion,
192
+ generatedAt: null,
193
+ producerName: null,
194
+ producerVersion: null,
195
+ role: null,
196
+ workflowId: packet.workflowId,
197
+ stageId: packet.stageId,
198
+ catalogSchemaVersion: packet.catalogSchemaVersion,
199
+ catalogVersion: packet.catalogVersion,
200
+ fixtureId: null,
201
+ caseId: null,
202
+ title: null,
203
+ };
204
+ }
205
+ function buildFullWorkflowLibraryMetadata(sourcePath, library) {
206
+ return {
207
+ sourceInstance: "fullWorkflowLibrary",
208
+ artifactKind: "full-workflow-library",
209
+ sourcePath,
210
+ schemaVersion: library.schemaVersion,
211
+ generatedAt: null,
212
+ producerName: null,
213
+ producerVersion: null,
214
+ role: null,
215
+ workflowId: null,
216
+ stageId: null,
217
+ catalogSchemaVersion: null,
218
+ catalogVersion: null,
219
+ fixtureId: library.fixtureId,
220
+ caseId: null,
221
+ title: library.title,
222
+ };
223
+ }
224
+ function buildEvaluationSummary(evaluation) {
225
+ if (evaluation.status !== "completed") {
226
+ return {
227
+ status: evaluation.status,
228
+ reason: evaluation.reason,
229
+ warnings: boundItems([]),
230
+ expectationMatches: boundItems([]),
231
+ observedEvidence: boundItems([]),
232
+ metrics: null,
233
+ };
234
+ }
235
+ return {
236
+ status: "completed",
237
+ reason: null,
238
+ warnings: boundItems(evaluation.warnings),
239
+ expectationMatches: boundItems(evaluation.expectationMatches.map(buildExpectationMatch)),
240
+ observedEvidence: boundItems(evaluation.observedEvidence.map(buildObservedEvidence)),
241
+ metrics: buildMetrics(evaluation.metrics),
242
+ };
243
+ }
244
+ function buildExpectationMatch(match) {
245
+ return {
246
+ expectationId: match.expectationId,
247
+ inclusion: match.inclusion,
248
+ sourceArtifact: match.sourceArtifact,
249
+ category: match.category,
250
+ targetKey: match.targetKey,
251
+ outcome: match.outcome,
252
+ matchedSourceInstances: match.matchedSourceInstances,
253
+ matchedSourceFieldPaths: match.matchedSourceFieldPaths,
254
+ };
255
+ }
256
+ function buildObservedEvidence(evidence) {
257
+ return {
258
+ sourceArtifact: evidence.sourceArtifact,
259
+ sourceInstance: evidence.sourceInstance,
260
+ category: evidence.category,
261
+ targetKey: evidence.targetKey,
262
+ sourceFieldPath: evidence.sourceFieldPath,
263
+ };
264
+ }
265
+ function buildMetrics(metrics) {
266
+ return {
267
+ requiredEvidenceRecall: buildRatioMetric(metrics.requiredEvidenceRecall),
268
+ allowedEvidenceCoverage: buildRatioMetric(metrics.allowedEvidenceCoverage),
269
+ forbiddenEvidenceInclusion: buildRatioMetric(metrics.forbiddenEvidenceInclusion),
270
+ irrelevantFileInclusion: buildCountMetric(metrics.irrelevantFileInclusion),
271
+ irrelevantInstructionInclusion: buildCountMetric(metrics.irrelevantInstructionInclusion),
272
+ requiredProvenanceRecall: buildRatioMetric(metrics.requiredProvenanceRecall),
273
+ responsibilityMappingCompleteness: boundItems(metrics.responsibilityMappingCompleteness.map(buildResponsibilityMapping)),
274
+ stateComparisons: boundItems(metrics.stateComparisons.map(buildStateComparison)),
275
+ contextSize: buildContextSize(metrics.contextSize),
276
+ consideredButUnselectedReads: buildCountMetric(metrics.consideredButUnselectedReads),
277
+ unnecessaryReads: buildCountMetric(metrics.unnecessaryReads),
278
+ targetImmutability: buildCountMetric(metrics.targetImmutability),
279
+ };
280
+ }
281
+ function buildRatioMetric(metric) {
282
+ return {
283
+ availability: metric.availability,
284
+ numerator: metric.numerator,
285
+ denominator: metric.denominator,
286
+ rate: metric.rate,
287
+ matchedExpectationIds: boundItems(metric.matchedExpectationIds),
288
+ missingExpectationIds: boundItems(metric.missingExpectationIds),
289
+ reason: metric.reason,
290
+ };
291
+ }
292
+ function buildCountMetric(metric) {
293
+ return {
294
+ availability: metric.availability,
295
+ count: metric.count,
296
+ evidenceKeys: boundItems(metric.evidenceKeys),
297
+ reason: metric.reason,
298
+ };
299
+ }
300
+ function buildResponsibilityMapping(mapping) {
301
+ return {
302
+ sourceArtifact: mapping.sourceArtifact,
303
+ sourceInstance: mapping.sourceInstance,
304
+ requested: mapping.requested,
305
+ operational: mapping.operational,
306
+ mappedCount: mapping.mappedCount,
307
+ partiallyMappedCount: mapping.partiallyMappedCount,
308
+ unmappedCount: mapping.unmappedCount,
309
+ notApplicableCount: mapping.notApplicableCount,
310
+ denominator: mapping.denominator,
311
+ mappedRate: mapping.mappedRate,
312
+ };
313
+ }
314
+ function buildStateComparison(comparison) {
315
+ return {
316
+ sourceArtifact: comparison.sourceArtifact,
317
+ sourceInstance: comparison.sourceInstance,
318
+ expectationFieldPath: comparison.expectationFieldPath,
319
+ artifactFieldPath: comparison.artifactFieldPath,
320
+ availability: comparison.availability,
321
+ expected: comparison.expected,
322
+ actual: comparison.actual,
323
+ matched: comparison.matched,
324
+ reason: comparison.reason,
325
+ };
326
+ }
327
+ function buildContextSize(size) {
328
+ return {
329
+ sources: boundItems(size.sources.map((source) => ({
330
+ sourceInstance: source.sourceInstance,
331
+ sourceKind: source.sourceKind,
332
+ characterCount: source.characterCount,
333
+ estimatedTokenCount: source.estimatedTokenCount,
334
+ }))),
335
+ totalCharacterCount: size.totalCharacterCount,
336
+ totalEstimatedTokenCount: size.totalEstimatedTokenCount,
337
+ tokenEstimateFormula: "ceil(characterCount / 4) per source",
338
+ };
339
+ }
340
+ function buildAssuranceSummary(assurance) {
341
+ return {
342
+ status: assurance.status,
343
+ repeatCount: assurance.repeatCount,
344
+ runRecords: boundItems(assurance.runRecords.map(buildRunRecord)),
345
+ determinism: buildDeterminism(assurance.determinism),
346
+ issues: boundItems(assurance.issues.map((issue) => ({
347
+ code: issue.code,
348
+ fieldPath: issue.fieldPath,
349
+ message: issue.message,
350
+ runNumber: issue.runNumber,
351
+ }))),
352
+ };
353
+ }
354
+ function buildRunRecord(record) {
355
+ const targetImmutability = record.targetImmutability;
356
+ if (targetImmutability.availability === "available") {
357
+ return {
358
+ runNumber: record.runNumber,
359
+ executionStatus: record.executionStatus,
360
+ evaluationStatus: record.evaluationStatus,
361
+ targetImmutabilityAvailability: "available",
362
+ targetImmutabilityStatus: targetImmutability.comparison.status,
363
+ newMutationCount: targetImmutability.comparison.newMutationCount,
364
+ targetImmutabilityReason: null,
365
+ mutations: boundItems(targetImmutability.comparison.mutations.map(buildTargetMutation)),
366
+ };
367
+ }
368
+ return {
369
+ runNumber: record.runNumber,
370
+ executionStatus: record.executionStatus,
371
+ evaluationStatus: record.evaluationStatus,
372
+ targetImmutabilityAvailability: "unavailable",
373
+ targetImmutabilityStatus: null,
374
+ newMutationCount: null,
375
+ targetImmutabilityReason: targetImmutability.reason,
376
+ mutations: boundItems([]),
377
+ };
378
+ }
379
+ function buildTargetMutation(mutation) {
380
+ return {
381
+ id: mutation.id,
382
+ kind: mutation.kind,
383
+ fieldPath: mutation.fieldPath,
384
+ before: mutation.before,
385
+ after: mutation.after,
386
+ };
387
+ }
388
+ function buildDeterminism(determinism) {
389
+ return {
390
+ availability: determinism.availability,
391
+ repeatCount: determinism.repeatCount,
392
+ deterministic: determinism.deterministic,
393
+ baselineSha256: determinism.baselineSha256,
394
+ runDigests: boundItems(determinism.runDigests.map((digest) => ({ runNumber: digest.runNumber, sha256: digest.sha256 }))),
395
+ mismatchRunNumbers: [...determinism.mismatchRunNumbers],
396
+ reason: determinism.reason,
397
+ };
398
+ }
@@ -1,7 +1,18 @@
1
1
  import path from "node:path";
2
+ import { buildContextStrategyComparisonV043Report } from "./buildContextStrategyComparisonV043Report.js";
3
+ const V043_BULK_ARRAY_KEYS = [
4
+ "v043StageContextExecutions",
5
+ "v043StageContextEvaluations",
6
+ "v043StageContextRunAssurance",
7
+ ];
2
8
  export function buildPluginExperimentReport(args) {
3
9
  const outputRoot = args.outputRoot ?? readString(args.run.metadata?.outputRoot) ?? null;
4
10
  const allOutcomes = args.run.cases.flatMap((experimentCase) => experimentCase.outcomes);
11
+ const contextStrategyComparisonV043 = buildContextStrategyComparisonV043Report(args.run);
12
+ const rawRun = { ...args.run, artifacts: relativizeArtifacts(args.run.artifacts, outputRoot) };
13
+ for (const key of V043_BULK_ARRAY_KEYS) {
14
+ delete rawRun[key];
15
+ }
5
16
  return {
6
17
  metadata: {
7
18
  generatedAt: args.generatedAt ?? new Date().toISOString(),
@@ -25,11 +36,9 @@ export function buildPluginExperimentReport(args) {
25
36
  failures: args.run.failures,
26
37
  skippedOutcomes: allOutcomes.filter((outcome) => outcome.status === "skipped"),
27
38
  findings: buildFindings(args.run),
28
- interpretation: buildInterpretation(args.run),
29
- rawRun: {
30
- ...args.run,
31
- artifacts: relativizeArtifacts(args.run.artifacts, outputRoot),
32
- },
39
+ contextStrategyComparisonV043,
40
+ interpretation: buildInterpretation(args.run, contextStrategyComparisonV043),
41
+ rawRun,
33
42
  };
34
43
  }
35
44
  function buildVariantSummary(variant, outcomes) {
@@ -85,7 +94,13 @@ function buildFindings(run) {
85
94
  ...skipped,
86
95
  ];
87
96
  }
88
- function buildInterpretation(run) {
97
+ function buildInterpretation(run, contextStrategyComparisonV043) {
98
+ if (run.pluginId === "context-strategy-comparison" && (contextStrategyComparisonV043?.summary.strategyCount ?? 0) > 0) {
99
+ return {
100
+ summary: `Stage-context evidence was recorded for ${contextStrategyComparisonV043.summary.strategyCount} strategy executions. Review each strategy independently; this report does not calculate a composite ranking or winning strategy.`,
101
+ recommendedNextStep: "Review required evidence, irrelevant inclusion, state comparisons, target immutability, determinism, and explicit unavailable or not-applicable metrics for each strategy.",
102
+ };
103
+ }
89
104
  if (run.pluginId === "context-strategy-comparison") {
90
105
  const tokenSavings = metricNumber(run.metrics, "average-token-savings-percent");
91
106
  const correctnessDelta = metricNumber(run.metrics, "average-correctness-delta");
@@ -0,0 +1 @@
1
+ export const V043_REPORT_DETAIL_LIMIT = 100;
@@ -2,3 +2,7 @@ export * from "./buildPluginExperimentReport.js";
2
2
  export * from "./experimentReportModel.js";
3
3
  export * from "./renderPluginExperimentReportHtml.js";
4
4
  export * from "./writePluginExperimentReports.js";
5
+ export * from "./contextStrategyComparisonV043ReportModel.js";
6
+ export { buildContextStrategyComparisonV043Report } from "./buildContextStrategyComparisonV043Report.js";
7
+ export { renderContextStrategyComparisonV043Html } from "./renderContextStrategyComparisonV043Html.js";
8
+ export { renderPluginExperimentReportText } from "./renderPluginExperimentReportText.js";