@dailephd/my-dev-kit-lab 0.6.3 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +7 -4
  3. package/benchmarks/contracts/context-window-scaling-cases.json +220 -0
  4. package/benchmarks/projects/README.md +3 -1
  5. package/benchmarks/projects/context-window-scaling-fixed-ts/README.md +14 -0
  6. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/carrier-depot-catalog-01.ts +302 -0
  7. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/course-module-catalog-06.ts +302 -0
  8. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/library-shelf-catalog-07.ts +302 -0
  9. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/sensor-station-catalog-05.ts +302 -0
  10. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/staff-rota-catalog-03.ts +302 -0
  11. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/supplier-contract-catalog-02.ts +302 -0
  12. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/vehicle-route-catalog-04.ts +302 -0
  13. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/archive-box-catalog-12.ts +302 -0
  14. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/clinic-ward-catalog-08.ts +302 -0
  15. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/greenhouse-bay-catalog-13.ts +302 -0
  16. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/harbor-berth-catalog-10.ts +302 -0
  17. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/kitchen-section-catalog-15.ts +302 -0
  18. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/market-stall-catalog-09.ts +302 -0
  19. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/station-platform-catalog-14.ts +302 -0
  20. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/workshop-bench-catalog-11.ts +302 -0
  21. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/archive-box-catalog-28.ts +302 -0
  22. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/carrier-depot-catalog-17.ts +302 -0
  23. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/clinic-ward-catalog-24.ts +302 -0
  24. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/course-module-catalog-22.ts +302 -0
  25. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/greenhouse-bay-catalog-29.ts +302 -0
  26. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/harbor-berth-catalog-26.ts +302 -0
  27. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/kitchen-section-catalog-31.ts +302 -0
  28. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/library-shelf-catalog-23.ts +302 -0
  29. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/market-stall-catalog-25.ts +302 -0
  30. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/sensor-station-catalog-21.ts +302 -0
  31. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/staff-rota-catalog-19.ts +302 -0
  32. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/station-platform-catalog-30.ts +302 -0
  33. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/supplier-contract-catalog-18.ts +302 -0
  34. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/vehicle-route-catalog-20.ts +302 -0
  35. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/warehouse-zone-catalog-16.ts +302 -0
  36. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/workshop-bench-catalog-27.ts +302 -0
  37. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/archive-box-catalog-44.ts +302 -0
  38. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/carrier-depot-catalog-33.ts +302 -0
  39. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/carrier-depot-catalog-49.ts +302 -0
  40. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/clinic-ward-catalog-40.ts +302 -0
  41. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/clinic-ward-catalog-56.ts +302 -0
  42. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/course-module-catalog-38.ts +302 -0
  43. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/course-module-catalog-54.ts +302 -0
  44. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/greenhouse-bay-catalog-45.ts +302 -0
  45. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/harbor-berth-catalog-42.ts +302 -0
  46. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/harbor-berth-catalog-58.ts +302 -0
  47. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/kitchen-section-catalog-47.ts +302 -0
  48. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/library-shelf-catalog-39.ts +302 -0
  49. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/library-shelf-catalog-55.ts +302 -0
  50. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/market-stall-catalog-41.ts +302 -0
  51. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/market-stall-catalog-57.ts +302 -0
  52. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/sensor-station-catalog-37.ts +302 -0
  53. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/sensor-station-catalog-53.ts +302 -0
  54. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/staff-rota-catalog-35.ts +302 -0
  55. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/staff-rota-catalog-51.ts +302 -0
  56. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/station-platform-catalog-46.ts +302 -0
  57. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/supplier-contract-catalog-34.ts +302 -0
  58. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/supplier-contract-catalog-50.ts +302 -0
  59. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/vehicle-route-catalog-36.ts +302 -0
  60. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/vehicle-route-catalog-52.ts +302 -0
  61. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/warehouse-zone-catalog-32.ts +302 -0
  62. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/warehouse-zone-catalog-48.ts +302 -0
  63. package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/workshop-bench-catalog-43.ts +302 -0
  64. package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/auditRedaction.ts +25 -0
  65. package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/inventoryReservation.ts +26 -0
  66. package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/invoiceTotals.ts +25 -0
  67. package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/shippingQuote.ts +32 -0
  68. package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/auditRedaction.test.ts +17 -0
  69. package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/inventoryReservation.test.ts +19 -0
  70. package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/invoiceTotals.test.ts +14 -0
  71. package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/shippingQuote.test.ts +19 -0
  72. package/dist/src/cli/help.js +19 -3
  73. package/dist/src/commands/runExperimentDescribeCommand.js +6 -0
  74. package/dist/src/commands/runExperimentRunCommand.js +118 -7
  75. package/dist/src/evaluation/syntheticRepository/config.js +304 -0
  76. package/dist/src/evaluation/syntheticRepository/evaluationCase.js +43 -0
  77. package/dist/src/evaluation/syntheticRepository/identity.js +41 -0
  78. package/dist/src/evaluation/syntheticRepository/index.js +16 -0
  79. package/dist/src/evaluation/syntheticRepository/inspection.js +92 -0
  80. package/dist/src/evaluation/syntheticRepository/layout.js +50 -0
  81. package/dist/src/evaluation/syntheticRepository/manifest.js +281 -0
  82. package/dist/src/evaluation/syntheticRepository/manifestVerification.js +112 -0
  83. package/dist/src/evaluation/syntheticRepository/materialize.js +170 -0
  84. package/dist/src/evaluation/syntheticRepository/planning.js +479 -0
  85. package/dist/src/evaluation/syntheticRepository/prng.js +47 -0
  86. package/dist/src/evaluation/syntheticRepository/renderPython.js +68 -0
  87. package/dist/src/evaluation/syntheticRepository/renderRepository.js +39 -0
  88. package/dist/src/evaluation/syntheticRepository/renderShared.js +93 -0
  89. package/dist/src/evaluation/syntheticRepository/renderTypeScript.js +82 -0
  90. package/dist/src/evaluation/syntheticRepository/topology.js +96 -0
  91. package/dist/src/evaluation/syntheticRepository/types.js +26 -0
  92. package/dist/src/experiments/defaultRegistry.js +2 -0
  93. package/dist/src/experiments/plugins/contextWindowScaling/cliBudgets.js +31 -0
  94. package/dist/src/experiments/plugins/contextWindowScaling/config.js +84 -0
  95. package/dist/src/experiments/plugins/contextWindowScaling/contextBudget.js +43 -0
  96. package/dist/src/experiments/plugins/contextWindowScaling/evaluation.js +36 -0
  97. package/dist/src/experiments/plugins/contextWindowScaling/execution.js +187 -0
  98. package/dist/src/experiments/plugins/contextWindowScaling/executionArtifact.js +15 -0
  99. package/dist/src/experiments/plugins/contextWindowScaling/executionArtifactReader.js +186 -0
  100. package/dist/src/experiments/plugins/contextWindowScaling/index.js +15 -0
  101. package/dist/src/experiments/plugins/contextWindowScaling/metadata.js +12 -0
  102. package/dist/src/experiments/plugins/contextWindowScaling/metrics.js +149 -0
  103. package/dist/src/experiments/plugins/contextWindowScaling/plugin.js +185 -0
  104. package/dist/src/experiments/plugins/contextWindowScaling/projectProfile.js +51 -0
  105. package/dist/src/experiments/plugins/contextWindowScaling/relevantFiles.js +76 -0
  106. package/dist/src/experiments/plugins/contextWindowScaling/successEvidence.js +60 -0
  107. package/dist/src/experiments/plugins/contextWindowScaling/syntheticInputs.js +56 -0
  108. package/dist/src/experiments/plugins/contextWindowScaling/types.js +1 -0
  109. package/dist/src/experiments/plugins/index.js +1 -0
  110. package/dist/src/experiments/plugins/warmIndexReuse/agentEvaluation.js +1 -1
  111. package/dist/src/plots/buildContextWindowScalingPlotData.js +96 -0
  112. package/dist/src/plots/index.js +1 -0
  113. package/dist/src/plots/writePlotArtifacts.js +12 -3
  114. package/dist/src/report/experiments/buildContextWindowScalingReport.js +84 -0
  115. package/dist/src/report/experiments/buildPluginExperimentReport.js +22 -2
  116. package/dist/src/report/experiments/contextWindowScalingReportModel.js +3 -0
  117. package/dist/src/report/experiments/index.js +4 -0
  118. package/dist/src/report/experiments/renderContextWindowScalingHtml.js +99 -0
  119. package/dist/src/report/experiments/renderContextWindowScalingText.js +108 -0
  120. package/dist/src/report/experiments/renderPluginExperimentReportHtml.js +3 -0
  121. package/dist/src/report/experiments/renderPluginExperimentReportText.js +8 -0
  122. package/docs/METRICS.md +29 -1
  123. package/package.json +1 -1
@@ -0,0 +1,84 @@
1
+ import { CONTEXT_WINDOW_SCALING_PLUGIN_ID } from "../../experiments/plugins/contextWindowScaling/metadata.js";
2
+ import { CONTEXT_WINDOW_SCALING_REPORT_SCHEMA_VERSION, MAX_REPORT_OMITTED_RELEVANT_FILES, } from "./contextWindowScalingReportModel.js";
3
+ /** Fixed wording; the report states observed evidence only and never ranks treatments. */
4
+ export const CONTEXT_WINDOW_SCALING_INTERPRETATION = [
5
+ "Estimated context tokens use the Lab deterministic heuristic (characters divided by four, rounded up); they are not provider billing telemetry or a provider model tokenizer result.",
6
+ "The configured budgets are experiment budgets, not claims about actual provider model context-window limits.",
7
+ "context-too-large is an expected measurement state under a budget and is not an operational execution failure.",
8
+ "When a context is too large for a budget, evaluation did not occur, so correctness is unavailable; unavailable correctness is not zero and is excluded from mean correctness.",
9
+ "Success combines context fit with the existing deterministic correctness pass evidence: success is true only when the context fits and correctness passes.",
10
+ "context-too-large is an available, not-successful outcome for the applicable budget and remains in the success-rate denominator.",
11
+ "Operational or evidence-unavailable cells are excluded from the success-rate denominator and are counted separately.",
12
+ "Omitted relevant files are benchmark-expected files that were not observed in the treatment's context provenance.",
13
+ "Omitted relevant files are not full retrieval precision or recall; no precision, recall, or irrelevant-context measure is calculated.",
14
+ "The deterministic fake-agent correctness path is context-independent in the current harness: correctness tests the existing answer-key and evaluation pipeline, not semantic model sensitivity to different context content.",
15
+ "Utilization is estimated context tokens divided by the budget, is not capped at 100 percent, and may exceed 100 for a context that is too large.",
16
+ "No composite score, winner, or ranking is calculated; the treatments are reported side by side.",
17
+ ];
18
+ /**
19
+ * Presents the aggregate and cell evidence already calculated on the run. It performs no fit,
20
+ * success, correctness, or utilization calculation of its own.
21
+ */
22
+ export function buildContextWindowScalingReport(run) {
23
+ if (run.pluginId !== CONTEXT_WINDOW_SCALING_PLUGIN_ID)
24
+ return null;
25
+ const candidate = run;
26
+ const evidence = candidate.executionEvidence;
27
+ const aggregate = candidate.aggregate;
28
+ if (!evidence || !aggregate) {
29
+ throw new Error("Invalid context-window-scaling report source: execution evidence and aggregate are required.");
30
+ }
31
+ if (aggregate.caseTreatmentContextSummaries.length !== evidence.length * aggregate.treatments.length) {
32
+ throw new Error("Invalid context-window-scaling report source: aggregate and execution evidence are inconsistent.");
33
+ }
34
+ const caseTreatmentContexts = aggregate.caseTreatmentContextSummaries.map((summary) => {
35
+ const relevant = summary.relevantFileEvidence;
36
+ return {
37
+ caseId: summary.caseId,
38
+ caseName: summary.caseName,
39
+ variantId: summary.variantId,
40
+ contextStatus: summary.contextStatus,
41
+ characterCount: summary.characterCount,
42
+ estimatedTokens: summary.estimatedTokens,
43
+ tokenCountMethod: summary.tokenCountMethod,
44
+ observedFileCount: summary.observedFileCount,
45
+ relevantFileStatus: relevant.status,
46
+ expectedRelevantFileCount: relevant.expectedRelevantFileCount,
47
+ observedExpectedFileCount: relevant.observedExpectedFileCount,
48
+ omittedRelevantFileCount: relevant.omittedRelevantFileCount,
49
+ omittedRelevantFiles: boundedList(relevant.omittedRelevantFiles),
50
+ relevantFileReason: relevant.reason,
51
+ };
52
+ });
53
+ const caseBudgetCells = evidence.flatMap((caseEvidence) => caseEvidence.treatments.flatMap((treatment) => treatment.budgetCells.map((cell) => ({
54
+ caseId: caseEvidence.caseId,
55
+ variantId: treatment.variantId,
56
+ contextEstimatedTokens: treatment.context.estimatedTokens,
57
+ ...structuredClone(cell),
58
+ }))));
59
+ return {
60
+ schemaVersion: CONTEXT_WINDOW_SCALING_REPORT_SCHEMA_VERSION,
61
+ budgets: [...aggregate.budgets],
62
+ treatments: [...aggregate.treatments],
63
+ tokenCountMethod: firstTokenCountMethod(aggregate.caseTreatmentContextSummaries.map((summary) => summary.tokenCountMethod)),
64
+ runSummary: { ...aggregate.runSummary },
65
+ budgetTreatmentSummaries: aggregate.budgetTreatmentSummaries.map((summary) => ({ ...summary })),
66
+ caseTreatmentContexts,
67
+ caseBudgetCells,
68
+ relevantFileSummary: { ...aggregate.relevantFileSummary },
69
+ interpretation: [...CONTEXT_WINDOW_SCALING_INTERPRETATION],
70
+ };
71
+ }
72
+ function boundedList(items) {
73
+ const displayed = items.slice(0, MAX_REPORT_OMITTED_RELEVANT_FILES);
74
+ return {
75
+ totalCount: items.length,
76
+ displayedCount: displayed.length,
77
+ omittedCount: items.length - displayed.length,
78
+ truncated: items.length > displayed.length,
79
+ items: [...displayed],
80
+ };
81
+ }
82
+ function firstTokenCountMethod(methods) {
83
+ return methods.find((method) => method !== null) ?? null;
84
+ }
@@ -2,6 +2,10 @@ import path from "node:path";
2
2
  import { buildContextStrategyComparisonV043Report } from "./buildContextStrategyComparisonV043Report.js";
3
3
  import { buildWarmIndexReuseReport } from "./buildWarmIndexReuseReport.js";
4
4
  import { buildIncrementalChangeStalenessPluginReport } from "./buildIncrementalChangeStalenessPluginReport.js";
5
+ import { buildContextWindowScalingReport } from "./buildContextWindowScalingReport.js";
6
+ // Bulk context-window-scaling evidence is presented by the typed report section; the complete
7
+ // evidence stays in context-window-scaling-execution.json.
8
+ const CONTEXT_WINDOW_SCALING_BULK_KEYS = ["executionEvidence", "aggregate"];
5
9
  const V043_BULK_ARRAY_KEYS = [
6
10
  "v043StageContextExecutions",
7
11
  "v043StageContextEvaluations",
@@ -13,10 +17,16 @@ export function buildPluginExperimentReport(args) {
13
17
  const contextStrategyComparisonV043 = buildContextStrategyComparisonV043Report(args.run);
14
18
  const warmIndexReuse = buildWarmIndexReuseReport(args.run);
15
19
  const incrementalChangeStaleness = buildIncrementalChangeStalenessPluginReport(args.run);
20
+ const contextWindowScaling = buildContextWindowScalingReport(args.run);
16
21
  const rawRun = { ...args.run, artifacts: relativizeArtifacts(args.run.artifacts, outputRoot) };
17
22
  for (const key of V043_BULK_ARRAY_KEYS) {
18
23
  delete rawRun[key];
19
24
  }
25
+ if (contextWindowScaling) {
26
+ for (const key of CONTEXT_WINDOW_SCALING_BULK_KEYS) {
27
+ delete rawRun[key];
28
+ }
29
+ }
20
30
  return {
21
31
  metadata: {
22
32
  generatedAt: args.generatedAt ?? new Date().toISOString(),
@@ -42,8 +52,9 @@ export function buildPluginExperimentReport(args) {
42
52
  findings: buildFindings(args.run),
43
53
  warmIndexReuse,
44
54
  incrementalChangeStaleness,
55
+ contextWindowScaling,
45
56
  contextStrategyComparisonV043,
46
- interpretation: buildInterpretation(args.run, contextStrategyComparisonV043, warmIndexReuse),
57
+ interpretation: buildInterpretation(args.run, contextStrategyComparisonV043, warmIndexReuse, contextWindowScaling),
47
58
  rawRun,
48
59
  };
49
60
  }
@@ -122,7 +133,16 @@ function affectedNeighborhoodSentence(report) {
122
133
  `reindex recommendations were recommended=${summary.recommendedReindexCount}, not-indicated=${summary.notIndicatedReindexCount}, unknown=${summary.unknownReindexRecommendationCount}. ` +
123
134
  "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.");
124
135
  }
125
- function buildInterpretation(run, contextStrategyComparisonV043, warmIndexReuse) {
136
+ function buildInterpretation(run, contextStrategyComparisonV043, warmIndexReuse, contextWindowScaling) {
137
+ if (contextWindowScaling) {
138
+ const summary = contextWindowScaling.runSummary;
139
+ return {
140
+ summary: `Context-window-scaling evidence covers ${summary.caseCount} case${summary.caseCount === 1 ? "" : "s"}, ${summary.treatmentCount} treatments, and ${summary.budgetCount} budget${summary.budgetCount === 1 ? "" : "s"} ` +
141
+ `(${summary.totalBudgetCellCount} budget cells): ${summary.evaluatedBudgetCellCount} evaluated, ${summary.contextTooLargeCellCount} context-too-large, ${summary.contextUnavailableCellCount} with unavailable context. ` +
142
+ "Context-too-large is an expected measurement state, not an execution failure. The treatments are reported side by side and are not ranked.",
143
+ recommendedNextStep: "Review the budget summary, per-case context sizes, and per-case budget matrix; unavailable correctness and success evidence are excluded from the rates and are never treated as zero.",
144
+ };
145
+ }
126
146
  if (run.pluginId === "warm-index-reuse" && warmIndexReuse) {
127
147
  const summary = warmIndexReuse.summary;
128
148
  const campaign = warmIndexReuse.agentCampaign;
@@ -0,0 +1,3 @@
1
+ export const CONTEXT_WINDOW_SCALING_REPORT_SCHEMA_VERSION = "my-dev-kit-lab-context-window-scaling-report-v1";
2
+ /** Presentation limit only; the full omitted identities stay in context-window-scaling-execution.json. */
3
+ export const MAX_REPORT_OMITTED_RELEVANT_FILES = 20;
@@ -20,3 +20,7 @@ export { buildIncrementalChangeStalenessPluginReport } from "./buildIncrementalC
20
20
  export { buildIncrementalChangeStalenessReportV2FromArtifact, findReportTreatment, findReportComparison, LIMITATIONS_V2 } from "./buildIncrementalChangeStalenessReportV2.js";
21
21
  export { buildIncrementalChangeStalenessReport, STALE_RISK_CLASSIFICATION_EXPLANATIONS } from "./buildIncrementalChangeStalenessReport.js";
22
22
  export { renderIncrementalChangeStalenessHtml } from "./renderIncrementalChangeStalenessHtml.js";
23
+ export * from "./contextWindowScalingReportModel.js";
24
+ export { buildContextWindowScalingReport, CONTEXT_WINDOW_SCALING_INTERPRETATION } from "./buildContextWindowScalingReport.js";
25
+ export { renderContextWindowScalingHtml } from "./renderContextWindowScalingHtml.js";
26
+ export { renderContextWindowScalingTextLines } from "./renderContextWindowScalingText.js";
@@ -0,0 +1,99 @@
1
+ import { formatContextWindowScalingCount, formatContextWindowScalingPercent, formatContextWindowScalingScore, } from "./renderContextWindowScalingText.js";
2
+ export function renderContextWindowScalingHtml(section) {
3
+ if (section === null) {
4
+ return `<section>
5
+ <h2>Context Window Scaling</h2>
6
+ <p>Not applicable to this plugin.</p>
7
+ </section>`;
8
+ }
9
+ const summary = section.runSummary;
10
+ return `<section>
11
+ <h2>Context Window Scaling</h2>
12
+ ${table(["Field", "Value"], [
13
+ ["Schema", section.schemaVersion],
14
+ ["Budgets (estimated context tokens)", section.budgets.join(", ")],
15
+ ["Treatments", section.treatments.join(", ")],
16
+ ["Token count method", section.tokenCountMethod ?? "unavailable"],
17
+ ...Object.entries(summary).map(([label, value]) => [label, String(value)]),
18
+ ])}
19
+ <h3>Budget Summary</h3>
20
+ ${table(["Budget", "Treatment", "Cells", "Fits", "Too large", "Context unavailable", "Success", "Not successful", "Success unavailable", "Success rate", "Correctness available", "Mean correctness", "Mean utilization", "Min utilization", "Max utilization"], section.budgetTreatmentSummaries.map((s) => [
21
+ String(s.contextBudgetTokens),
22
+ s.variantId,
23
+ String(s.totalCellCount),
24
+ String(s.fitCount),
25
+ String(s.contextTooLargeCount),
26
+ String(s.contextUnavailableCount),
27
+ String(s.successfulCellCount),
28
+ String(s.notSuccessfulCellCount),
29
+ String(s.successEvidenceUnavailableCount),
30
+ formatContextWindowScalingPercent(s.successRatePercent),
31
+ String(s.correctnessAvailableCount),
32
+ formatContextWindowScalingScore(s.meanCorrectnessScore),
33
+ formatContextWindowScalingPercent(s.meanContextBudgetUtilizationPercent),
34
+ formatContextWindowScalingPercent(s.minContextBudgetUtilizationPercent),
35
+ formatContextWindowScalingPercent(s.maxContextBudgetUtilizationPercent),
36
+ ]))}
37
+ <h3>Case Context Evidence</h3>
38
+ <p class="muted">Context does not vary by budget, so there is one row per case and treatment.</p>
39
+ ${table(["Case", "Treatment", "Context", "Characters", "Estimated tokens", "Token method", "Observed files", "Relevant-file evidence", "Expected relevant files", "Observed expected files", "Omitted relevant files"], section.caseTreatmentContexts.map((c) => [
40
+ c.caseId,
41
+ c.variantId,
42
+ c.contextStatus,
43
+ formatContextWindowScalingCount(c.characterCount),
44
+ formatContextWindowScalingCount(c.estimatedTokens),
45
+ c.tokenCountMethod ?? "unavailable",
46
+ formatContextWindowScalingCount(c.observedFileCount),
47
+ c.relevantFileStatus,
48
+ String(c.expectedRelevantFileCount),
49
+ formatContextWindowScalingCount(c.observedExpectedFileCount),
50
+ formatContextWindowScalingCount(c.omittedRelevantFileCount),
51
+ ]))}
52
+ <h3>Omitted Relevant Files</h3>
53
+ <p class="muted">Benchmark-expected files not observed in the treatment context. Not retrieval precision or recall.</p>
54
+ ${table(["Evidence available", "Unavailable", "Not applicable", "Total omitted"], [[
55
+ String(section.relevantFileSummary.relevantFileEvidenceAvailableCount),
56
+ String(section.relevantFileSummary.relevantFileEvidenceUnavailableCount),
57
+ String(section.relevantFileSummary.relevantFileEvidenceNotApplicableCount),
58
+ String(section.relevantFileSummary.totalOmittedRelevantFileCount),
59
+ ]])}
60
+ ${section.caseTreatmentContexts
61
+ .filter((c) => c.relevantFileStatus === "available" && (c.omittedRelevantFileCount ?? 0) > 0)
62
+ .map((c) => `<p><code>${escapeHtml(c.caseId)}</code> / ${escapeHtml(c.variantId)}: omitted ${c.omittedRelevantFiles.totalCount}; displayed ${c.omittedRelevantFiles.displayedCount} of ${c.omittedRelevantFiles.totalCount}; omitted from display ${c.omittedRelevantFiles.omittedCount}; truncated ${c.omittedRelevantFiles.truncated ? "yes" : "no"}</p>${list(c.omittedRelevantFiles.items)}`)
63
+ .join("\n ")}
64
+ <h3>Per-Case Budget Matrix</h3>
65
+ ${table(["Case", "Treatment", "Budget", "Estimated context tokens", "Fit", "Utilization", "Evaluation", "Correctness", "Correctness score", "Correctness pass", "Success evidence", "Success", "Success reason"], section.caseBudgetCells.map((cell) => [
66
+ cell.caseId,
67
+ cell.variantId,
68
+ String(cell.contextBudgetTokens),
69
+ formatContextWindowScalingCount(cell.contextEstimatedTokens),
70
+ cell.contextFitStatus,
71
+ formatContextWindowScalingPercent(cell.contextBudgetUtilizationPercent),
72
+ cell.evaluationStatus,
73
+ cell.correctness.availability,
74
+ formatContextWindowScalingScore(cell.correctness.score),
75
+ cell.correctness.pass === null ? "unavailable" : String(cell.correctness.pass),
76
+ cell.successEvidence.status,
77
+ cell.successEvidence.success === null ? "unavailable" : String(cell.successEvidence.success),
78
+ cell.successEvidence.reason,
79
+ ]))}
80
+ <h3>Interpretation And Limitations</h3>
81
+ ${list(section.interpretation)}
82
+ </section>`;
83
+ }
84
+ function list(items) {
85
+ return `<ul>${items.map((item) => `<li>${escapeHtml(item)}</li>`).join("")}</ul>`;
86
+ }
87
+ function table(headers, rows) {
88
+ return `<table><thead><tr>${headers.map((header) => `<th>${escapeHtml(header)}</th>`).join("")}</tr></thead><tbody>${rows
89
+ .map((row) => `<tr>${row.map((cell) => `<td>${escapeHtml(cell)}</td>`).join("")}</tr>`)
90
+ .join("")}</tbody></table>`;
91
+ }
92
+ function escapeHtml(value) {
93
+ return String(value ?? "")
94
+ .replaceAll("&", "&amp;")
95
+ .replaceAll("<", "&lt;")
96
+ .replaceAll(">", "&gt;")
97
+ .replaceAll('"', "&quot;")
98
+ .replaceAll("'", "&#39;");
99
+ }
@@ -0,0 +1,108 @@
1
+ // Render-time formatting only; the JSON report keeps exact unrounded values.
2
+ // Rule: percent values use 2 decimals plus "%", correctness scores use 4 decimals, null is "unavailable".
3
+ export function formatContextWindowScalingPercent(value) {
4
+ return value === null ? "unavailable" : `${value.toFixed(2)}%`;
5
+ }
6
+ export function formatContextWindowScalingScore(value) {
7
+ return value === null ? "unavailable" : value.toFixed(4);
8
+ }
9
+ export function formatContextWindowScalingCount(value) {
10
+ return value === null ? "unavailable" : String(value);
11
+ }
12
+ function clean(value) {
13
+ return String(value).replace(/[\u0000-\u001f\u007f]/g, " ");
14
+ }
15
+ function row(parts) {
16
+ return `- ${parts.map(([label, value]) => `${label}: ${clean(value)}`).join(" | ")}`;
17
+ }
18
+ /** Lines for the "Context Window Scaling" section; every value comes from the report model. */
19
+ export function renderContextWindowScalingTextLines(section) {
20
+ const lines = [];
21
+ lines.push(`Schema: ${clean(section.schemaVersion)}`);
22
+ lines.push(`Budgets (estimated context tokens): ${section.budgets.join(", ")}`);
23
+ lines.push(`Treatments: ${section.treatments.join(", ")}`);
24
+ lines.push(`Token Count Method: ${clean(section.tokenCountMethod ?? "unavailable")}`);
25
+ lines.push("Run Summary:");
26
+ const summary = section.runSummary;
27
+ for (const [label, value] of Object.entries(summary)) {
28
+ lines.push(`${label}: ${value}`);
29
+ }
30
+ lines.push("Budget Summary (one row per budget and treatment):");
31
+ for (const s of section.budgetTreatmentSummaries) {
32
+ lines.push(row([
33
+ ["Budget", s.contextBudgetTokens],
34
+ ["Treatment", s.variantId],
35
+ ["Cells", s.totalCellCount],
36
+ ["Fits", s.fitCount],
37
+ ["Too Large", s.contextTooLargeCount],
38
+ ["Context Unavailable", s.contextUnavailableCount],
39
+ ["Success", s.successfulCellCount],
40
+ ["Not Successful", s.notSuccessfulCellCount],
41
+ ["Success Unavailable", s.successEvidenceUnavailableCount],
42
+ ["Success Rate", formatContextWindowScalingPercent(s.successRatePercent)],
43
+ ["Correctness Available", s.correctnessAvailableCount],
44
+ ["Mean Correctness", formatContextWindowScalingScore(s.meanCorrectnessScore)],
45
+ ["Mean Utilization", formatContextWindowScalingPercent(s.meanContextBudgetUtilizationPercent)],
46
+ ["Min Utilization", formatContextWindowScalingPercent(s.minContextBudgetUtilizationPercent)],
47
+ ["Max Utilization", formatContextWindowScalingPercent(s.maxContextBudgetUtilizationPercent)],
48
+ ]));
49
+ }
50
+ lines.push("Case Context Evidence (one row per case and treatment; context does not vary by budget):");
51
+ for (const c of section.caseTreatmentContexts) {
52
+ lines.push(row([
53
+ ["Case", c.caseId],
54
+ ["Treatment", c.variantId],
55
+ ["Context", c.contextStatus],
56
+ ["Characters", formatContextWindowScalingCount(c.characterCount)],
57
+ ["Estimated Tokens", formatContextWindowScalingCount(c.estimatedTokens)],
58
+ ["Token Method", c.tokenCountMethod ?? "unavailable"],
59
+ ["Observed Files", formatContextWindowScalingCount(c.observedFileCount)],
60
+ ["Relevant File Evidence", c.relevantFileStatus],
61
+ ["Expected Relevant Files", c.expectedRelevantFileCount],
62
+ ["Observed Expected Files", formatContextWindowScalingCount(c.observedExpectedFileCount)],
63
+ ["Omitted Relevant Files", formatContextWindowScalingCount(c.omittedRelevantFileCount)],
64
+ ]));
65
+ }
66
+ lines.push("Omitted Relevant Files (benchmark-expected files not observed in the treatment context):");
67
+ lines.push(row([
68
+ ["Evidence Available", section.relevantFileSummary.relevantFileEvidenceAvailableCount],
69
+ ["Unavailable", section.relevantFileSummary.relevantFileEvidenceUnavailableCount],
70
+ ["Not Applicable", section.relevantFileSummary.relevantFileEvidenceNotApplicableCount],
71
+ ["Total Omitted", section.relevantFileSummary.totalOmittedRelevantFileCount],
72
+ ]));
73
+ for (const c of section.caseTreatmentContexts) {
74
+ if (c.relevantFileStatus === "available" && (c.omittedRelevantFileCount ?? 0) > 0) {
75
+ const list = c.omittedRelevantFiles;
76
+ lines.push(`${clean(c.caseId)} / ${c.variantId}: omitted ${list.totalCount}; displayed ${list.displayedCount} of ${list.totalCount}; omitted from display ${list.omittedCount}; truncated ${list.truncated ? "yes" : "no"}`);
77
+ for (const file of list.items) {
78
+ lines.push(` - ${clean(file)}`);
79
+ }
80
+ }
81
+ else if (c.relevantFileStatus !== "available" && c.relevantFileReason) {
82
+ lines.push(`${clean(c.caseId)} / ${c.variantId}: ${c.relevantFileStatus} (${clean(c.relevantFileReason)})`);
83
+ }
84
+ }
85
+ lines.push("Per-Case Budget Matrix (one row per case, treatment, and budget):");
86
+ for (const cell of section.caseBudgetCells) {
87
+ lines.push(row([
88
+ ["Case", cell.caseId],
89
+ ["Treatment", cell.variantId],
90
+ ["Budget", cell.contextBudgetTokens],
91
+ ["Estimated Context Tokens", formatContextWindowScalingCount(cell.contextEstimatedTokens)],
92
+ ["Fit", cell.contextFitStatus],
93
+ ["Utilization", formatContextWindowScalingPercent(cell.contextBudgetUtilizationPercent)],
94
+ ["Evaluation", cell.evaluationStatus],
95
+ ["Correctness", cell.correctness.availability],
96
+ ["Correctness Score", formatContextWindowScalingScore(cell.correctness.score)],
97
+ ["Correctness Pass", cell.correctness.pass === null ? "unavailable" : cell.correctness.pass],
98
+ ["Success Evidence", cell.successEvidence.status],
99
+ ["Success", cell.successEvidence.success === null ? "unavailable" : cell.successEvidence.success],
100
+ ["Success Reason", cell.successEvidence.reason],
101
+ ]));
102
+ }
103
+ lines.push("Interpretation And Limitations:");
104
+ for (const item of section.interpretation) {
105
+ lines.push(`- ${clean(item)}`);
106
+ }
107
+ return lines;
108
+ }
@@ -1,6 +1,7 @@
1
1
  import { renderContextStrategyComparisonV043Html } from "./renderContextStrategyComparisonV043Html.js";
2
2
  import { renderWarmIndexReuseHtml } from "./renderWarmIndexReuseHtml.js";
3
3
  import { renderIncrementalChangeStalenessHtml } from "./renderIncrementalChangeStalenessHtml.js";
4
+ import { renderContextWindowScalingHtml } from "./renderContextWindowScalingHtml.js";
4
5
  export function renderPluginExperimentReportHtml(report) {
5
6
  return `<!DOCTYPE html>
6
7
  <html lang="en">
@@ -102,6 +103,8 @@ export function renderPluginExperimentReportHtml(report) {
102
103
 
103
104
  ${renderIncrementalChangeStalenessHtml(report.incrementalChangeStaleness)}
104
105
 
106
+ ${renderContextWindowScalingHtml(report.contextWindowScaling)}
107
+
105
108
  <section>
106
109
  <h2>Warnings, Skips, And Failures</h2>
107
110
  ${report.findings.length ? table(["Severity", "Code", "Message", "Variant", "Case"], report.findings.map((finding) => [
@@ -2,6 +2,7 @@ import { STALE_RISK_CLASSIFICATION_EXPLANATIONS } from "./buildIncrementalChange
2
2
  import { isV2ReportSection } from "./buildIncrementalChangeStalenessReportV2.js";
3
3
  import { renderIncrementalChangeStalenessSectionV2 } from "./renderIncrementalChangeStalenessTextV2.js";
4
4
  import { REINDEX_RECOMMENDATION_EXPLANATIONS } from "./buildWarmIndexReuseReport.js";
5
+ import { renderContextWindowScalingTextLines } from "./renderContextWindowScalingText.js";
5
6
  function sanitizeScalar(value) {
6
7
  const text = String(value);
7
8
  let result = "";
@@ -663,6 +664,13 @@ export function renderPluginExperimentReportText(report) {
663
664
  renderWarmIndexReuseSection(lines, report.warmIndexReuse);
664
665
  pushSection(lines, "Incremental-Change And Staleness Evidence");
665
666
  renderIncrementalChangeStalenessSection(lines, report.incrementalChangeStaleness);
667
+ pushSection(lines, "Context Window Scaling");
668
+ if (report.contextWindowScaling === null) {
669
+ lines.push("Not applicable to this plugin.");
670
+ }
671
+ else {
672
+ lines.push(...renderContextWindowScalingTextLines(report.contextWindowScaling));
673
+ }
666
674
  pushSection(lines, "Warnings, Skips, And Failures");
667
675
  pushDashList(lines, report.findings.map((finding) => `${finding.severity} ${finding.code} ${finding.message} variant=${finding.variantId ?? ""} case=${finding.caseId ?? ""}`));
668
676
  pushSection(lines, "Artifacts");
package/docs/METRICS.md CHANGED
@@ -596,6 +596,34 @@ All six metrics are warm-side only (they are not on the raw-full-file side, beca
596
596
 
597
597
  **Observational only.** The evidence never triggers reindexing, suppresses or alters warm retrieval, or changes execution, provider, agent, correctness, or token-evidence status. It uses only the baseline graph of the prepared index: there is no graph-diff, refreshed-index, or stale-versus-refreshed comparison.
598
598
 
599
+ ## Context-window scaling evidence (v0.7.0)
600
+
601
+ Status: **released in v0.7.0**. The `context-window-scaling` plugin compares `raw-full-file` and `my-dev-kit-guided` treatment contexts against selected estimated-token budgets. By default it runs the bundled case catalog against the fixed self target; the v0.7.1 `--synthetic-config` input runs the same metrics over deterministic generated repositories without changing any formula below.
602
+
603
+ ### Measurement and budget-cell semantics
604
+
605
+ - **Estimated tokens:** context construction records character count and an estimated token count using the Lab's deterministic `ceil(characters / 4)` heuristic. It is not a provider tokenizer result, model-window measurement, or billing telemetry.
606
+ - **Budget values:** defaults are 8192, 16384, 32768, and 65536 tokens (shown as 8k, 16k, 32k, and 64k). Users can select other positive safe integers. Duplicate values after normalization are rejected; accepted budgets are sorted ascending.
607
+ - **Context fit:** `fits` when estimated context tokens are less than or equal to the selected budget; `context-too-large` when they exceed it; `unavailable` when context measurement is unavailable. This classification does not truncate or reconstruct the context. Each treatment's context is built once, independent of its budgets.
608
+ - **Budget utilization:** `contextBudgetUtilizationPercent = estimatedContextTokens / budget * 100`. It is not capped at 100 percent, so an over-budget context can have utilization greater than 100. It is unavailable when context size is unavailable.
609
+ - **Correctness:** the existing deterministic fake-agent answer-key evaluator runs no more than once per treatment and is shared by every budget cell where that treatment's context fits. Correctness is unavailable for a `context-too-large` cell and is not converted to zero. This harness's evaluation is context-independent; it does not estimate how a real model's correctness would change with the supplied context.
610
+ - **Success:** success is true only when the context fits and the available correctness evidence passes. A too-large context is an available unsuccessful cell with reason `context-too-large`, even though no evaluation ran. Operational or evidence-unavailable cells remain unavailable and are excluded from success-rate denominators. Thus context-too-large cells count as not successful, while unavailable cells do not.
611
+ - **Omitted relevant files:** benchmark-expected relevant files absent from the treatment's observed context provenance. This is an evidence count/list, not retrieval precision, recall, or an irrelevant-context ratio. The report bounds displayed omitted paths and retains total/displayed/omitted counts.
612
+
613
+ ### Aggregate and per-cell metrics
614
+
615
+ `aggregateContextWindowScaling` in `src/experiments/plugins/contextWindowScaling/metrics.ts` owns the per-budget and run summaries. `buildContextWindowScalingReport.ts` presents these results without recalculating fit, utilization, success, or correctness.
616
+
617
+ For each budget and treatment, aggregate evidence includes `fitCount`, `contextTooLargeCount`, `contextUnavailableCount`, `successfulCellCount`, `notSuccessfulCellCount`, success-evidence availability counts, `successRatePercent`, correctness availability counts and `meanCorrectnessScore`, and availability counts plus mean/min/max context-budget utilization. Success rate is successful cells divided by success-evidence-available cells; it is null when none are available. Mean correctness averages only available scores and is null when none are available. Utilization summaries include only measured values and remain uncapped.
618
+
619
+ The generic `ExperimentMetric` projection emits run-level case and budget counts, plus per-budget/per-treatment fit count, too-large count, successful count, success rate, mean correctness, and mean utilization. Per-case treatment outcomes carry context estimated tokens, omitted relevant file count when available, and budget-scoped utilization, correctness score, and success evidence. Unavailable values remain null/unavailable with their evidence status; no value is fabricated as zero.
620
+
621
+ The report artifact schema is `my-dev-kit-lab-context-window-scaling-report-v1`. It includes run summaries, budget-treatment summaries, per-treatment context measurements, budget cells, relevant-file summary, and fixed interpretation limits. The execution artifact is `context-window-scaling-execution.json` (`my-dev-kit-lab-context-window-scaling-execution-v1`) and does not embed context text.
622
+
623
+ **Synthetic-repository runs (v0.7.1).** The synthetic input introduces no new scientific metric: fit, utilization, correctness, success, and omitted-relevant-file semantics, the execution artifact schema, the report schema, and the plot set are identical to the bundled-corpus run. Each generated repository's `synthetic-repository-manifest.json` records generation evidence (per-file byte length, character count, SHA-256, generated-content estimated tokens, aggregate totals, and `repositoryContentIdentity`); these are reproducibility measurements, not context-window outcome metrics. The raw-full-file treatment context is measured by the existing baseline, which adds file headers and separators, so its estimated tokens differ from the manifest's generated-content estimate. Retrieval precision/recall remains v0.8.0 scope.
624
+
625
+ There is no composite score, winner, or ranking. Budgets are experiment thresholds, not assertions about actual provider context-window capacities. See [COMMANDS.md](COMMANDS.md), [WORKFLOWS.md](WORKFLOWS.md), and [ARCHITECTURE.md](ARCHITECTURE.md).
626
+
599
627
  ## Incremental-change and staleness evidence (v0.6.2)
600
628
 
601
629
  The `incremental-change-staleness` plugin reuses the six existing v0.6.1 affected-neighborhood numeric metrics unchanged (`changedFileCount`, `changedSymbolCount`, `affectedNodeCount`, `affectedEdgeCount`, `taskOverlapCount`, `taskOverlapPercent`; see "Affected-neighborhood metrics (v0.6.1)" above) and adds no new numeric formula.
@@ -630,7 +658,7 @@ The `incremental-change-staleness` plugin reuses the six existing v0.6.1 affecte
630
658
 
631
659
  **Report presentation.** `report.incrementalChangeStaleness` holds `scenarioCount`, `readyScenarioCount`, `failedScenarioCount`, `observedStaleRegressionCount`, `noObservedStaleRegressionCount`, `inconclusiveCount`, per-scenario evidence (lifecycle, both treatments in order, and the comparison), and fixed limitations text. There is no overall score, grade, winner, best-treatment, or safe-to-skip-reindex field anywhere in the report or the persisted execution artifact.
632
660
 
633
- ### Partial-refresh treatment evidence (v0.6.3, current release)
661
+ ### Partial-refresh treatment evidence (v0.6.3, retained in current release)
634
662
 
635
663
  The `incremental-change-staleness` plugin now compares four treatments (`stale-index`, `changed-files-refresh`, `affected-neighborhood-refresh`, `full-refresh`). It defines no new formula. Two evidence families must not be merged:
636
664
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dailephd/my-dev-kit-lab",
3
- "version": "0.6.3",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "description": "Evidence, benchmark, and evaluation companion for my-dev-kit.",
6
6
  "bin": {