@dailephd/my-dev-kit-lab 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +26 -10
  3. package/benchmarks/contracts/benchmark-project-profiles.json +14 -14
  4. package/benchmarks/contracts/warm-index-benchmark-cases.json +764 -0
  5. package/dist/src/agents/adapters/claudeAdapter.js +47 -4
  6. package/dist/src/agents/adapters/codexAdapter.js +64 -5
  7. package/dist/src/cli/help.js +22 -1
  8. package/dist/src/commands/runExperimentDescribeCommand.js +6 -1
  9. package/dist/src/commands/runExperimentRunCommand.js +87 -5
  10. package/dist/src/commands/runWarmIndexCampaignPresentation.js +64 -0
  11. package/dist/src/core/runMeasuredCommand.js +49 -10
  12. package/dist/src/evaluation/benchmarkMetadata.js +191 -1
  13. package/dist/src/evaluation/projectComplexity.js +1 -1
  14. package/dist/src/evaluation/readEvaluationCases.js +7 -1
  15. package/dist/src/evaluation/types.js +1 -1
  16. package/dist/src/experiments/plugins/warmIndexReuse/agentEvaluation.js +233 -0
  17. package/dist/src/experiments/plugins/warmIndexReuse/campaignPresets.js +83 -0
  18. package/dist/src/experiments/plugins/warmIndexReuse/config.js +51 -0
  19. package/dist/src/experiments/plugins/warmIndexReuse/fakeAgentEvaluation.js +6 -118
  20. package/dist/src/experiments/plugins/warmIndexReuse/index.js +3 -1
  21. package/dist/src/experiments/plugins/warmIndexReuse/metrics.js +35 -11
  22. package/dist/src/experiments/plugins/warmIndexReuse/plugin.js +50 -14
  23. package/dist/src/experiments/plugins/warmIndexReuse/realAgentPrompt.js +52 -0
  24. package/dist/src/experiments/plugins/warmIndexReuse/selection.js +35 -0
  25. package/dist/src/gallery/index.js +1 -0
  26. package/dist/src/gallery/writeGalleryManifest.js +5 -1
  27. package/dist/src/gallery/writeWarmIndexCampaignGallery.js +116 -0
  28. package/dist/src/plots/buildWarmIndexPlotData.js +21 -2
  29. package/dist/src/report/experiments/buildPluginExperimentReport.js +35 -8
  30. package/dist/src/report/experiments/buildWarmIndexReuseReport.js +138 -12
  31. package/dist/src/report/experiments/renderPluginExperimentReportText.js +35 -12
  32. package/dist/src/report/experiments/renderWarmIndexReuseHtml.js +45 -14
  33. package/docs/METRICS.md +33 -3
  34. package/package.json +1 -1
@@ -0,0 +1,764 @@
1
+ [
2
+ {
3
+ "id": "warm-medium-import-dedupe",
4
+ "title": "Warm-index task workflow import and dedupe retrieval",
5
+ "benchmarkProject": "task-workflow-medium-ts",
6
+ "projectProfileRef": "task-workflow-medium-ts",
7
+ "taskLocality": "cross-module",
8
+ "targetRoot": "benchmarks/projects/task-workflow-medium-ts",
9
+ "sourceRoots": ["src", "tests"],
10
+ "query": "import tasks duplicate normalized title project validation deterministic id",
11
+ "expectedFiles": [
12
+ "src/services/importTasks.ts",
13
+ "src/store/taskStore.ts",
14
+ "src/validation/taskValidation.ts"
15
+ ],
16
+ "expectedSymbols": ["importTasks", "validateImportInput", "findDuplicate", "createTask"],
17
+ "answerKey": {
18
+ "expectedFiles": [
19
+ "src/services/importTasks.ts",
20
+ "src/store/taskStore.ts",
21
+ "src/validation/taskValidation.ts"
22
+ ],
23
+ "expectedSymbols": ["importTasks", "validateImportInput", "findDuplicate", "createTask"],
24
+ "expectedFacts": [
25
+ {
26
+ "id": "warm-medium-import-validates-title-and-project",
27
+ "text": "importTasks validates normalized task titles and project ids before inserting records.",
28
+ "weight": 1,
29
+ "required": true
30
+ },
31
+ {
32
+ "id": "warm-medium-import-skips-duplicates-by-project-and-normalized-title",
33
+ "text": "importTasks skips duplicates when a task with the same normalized title already exists in the same project.",
34
+ "weight": 1,
35
+ "required": true
36
+ },
37
+ {
38
+ "id": "warm-medium-import-keeps-deterministic-task-sequences",
39
+ "text": "New imported tasks still receive deterministic ids such as task-1 and task-2 from the shared store sequence.",
40
+ "weight": 1,
41
+ "required": true
42
+ }
43
+ ],
44
+ "minimumCorrectFacts": 3,
45
+ "notes": "Cross-module retrieval spanning the import service, validation, and store logic."
46
+ },
47
+ "rawIncludeGlobs": ["src/**/*", "tests/**/*"],
48
+ "notes": "v0.5.1 warm-index seed case grounded in the existing task-workflow-import-dedup behavior."
49
+ },
50
+ {
51
+ "id": "warm-medium-create-project-task",
52
+ "title": "Warm-index create task with project metadata",
53
+ "benchmarkProject": "task-workflow-medium-ts",
54
+ "projectProfileRef": "task-workflow-medium-ts",
55
+ "taskLocality": "cross-module",
56
+ "targetRoot": "benchmarks/projects/task-workflow-medium-ts",
57
+ "sourceRoots": ["src", "tests"],
58
+ "query": "create task validate project title priority tags normalize tags deterministic id",
59
+ "expectedFiles": [
60
+ "src/services/createTask.ts",
61
+ "src/validation/taskValidation.ts",
62
+ "src/store/taskStore.ts",
63
+ "src/utils/deterministicId.ts"
64
+ ],
65
+ "expectedSymbols": [
66
+ "createTask",
67
+ "validateTaskTitle",
68
+ "validateProjectId",
69
+ "normalizeTags",
70
+ "TaskWorkflowStore",
71
+ "createDeterministicId"
72
+ ],
73
+ "answerKey": {
74
+ "expectedFiles": [
75
+ "src/services/createTask.ts",
76
+ "src/validation/taskValidation.ts",
77
+ "src/store/taskStore.ts",
78
+ "src/utils/deterministicId.ts"
79
+ ],
80
+ "expectedSymbols": [
81
+ "createTask",
82
+ "validateTaskTitle",
83
+ "validateProjectId",
84
+ "normalizeTags",
85
+ "TaskWorkflowStore",
86
+ "createDeterministicId"
87
+ ],
88
+ "expectedFacts": [
89
+ {
90
+ "id": "warm-medium-create-validates-title",
91
+ "text": "createTask validates the title with validateTaskTitle, which collapses whitespace and rejects an empty title with \"Task title must not be empty.\"",
92
+ "weight": 1,
93
+ "required": true
94
+ },
95
+ {
96
+ "id": "warm-medium-create-validates-project-before-storing",
97
+ "text": "createTask validates the projectId with validateProjectId and throws \"Unknown project id: <id>\" when the store has no such project, before the task is stored.",
98
+ "weight": 1,
99
+ "required": true
100
+ },
101
+ {
102
+ "id": "warm-medium-create-normalizes-tags",
103
+ "text": "Tags are normalized with normalizeTags (trimmed, lowercased, empty values dropped, de-duplicated, and sorted) before the task is stored.",
104
+ "weight": 1,
105
+ "required": true
106
+ },
107
+ {
108
+ "id": "warm-medium-create-uses-deterministic-sequence",
109
+ "text": "TaskWorkflowStore.createTask assigns the id with createDeterministicId(\"task\", sequence) from the store's shared incrementing sequence, producing ids such as task-1 and task-2.",
110
+ "weight": 1,
111
+ "required": true
112
+ },
113
+ {
114
+ "id": "warm-medium-create-starts-incomplete",
115
+ "text": "A newly created task is stored with completed set to false.",
116
+ "weight": 1,
117
+ "required": true
118
+ }
119
+ ],
120
+ "minimumCorrectFacts": 4,
121
+ "notes": "Cross-module: the create service composes validation, the store, and the deterministic id utility."
122
+ },
123
+ "rawIncludeGlobs": ["src/**/*", "tests/**/*"],
124
+ "notes": "v0.5.1 warm-index medium case for task creation."
125
+ },
126
+ {
127
+ "id": "warm-medium-complete-idempotent",
128
+ "title": "Warm-index idempotent task completion",
129
+ "benchmarkProject": "task-workflow-medium-ts",
130
+ "projectProfileRef": "task-workflow-medium-ts",
131
+ "taskLocality": "localized",
132
+ "targetRoot": "benchmarks/projects/task-workflow-medium-ts",
133
+ "sourceRoots": ["src", "tests"],
134
+ "query": "complete task by id idempotent completedAt unknown task",
135
+ "expectedFiles": ["src/services/completeTask.ts", "src/store/taskStore.ts"],
136
+ "expectedSymbols": ["completeTask", "TaskWorkflowStore"],
137
+ "answerKey": {
138
+ "expectedFiles": ["src/services/completeTask.ts", "src/store/taskStore.ts"],
139
+ "expectedSymbols": ["completeTask", "TaskWorkflowStore"],
140
+ "expectedFacts": [
141
+ {
142
+ "id": "warm-medium-complete-targets-task-by-id",
143
+ "text": "completeTask(store, taskId) changes one task by id through TaskWorkflowStore.updateTask.",
144
+ "weight": 1,
145
+ "required": true
146
+ },
147
+ {
148
+ "id": "warm-medium-complete-sets-completed-at",
149
+ "text": "The first completion sets completed to true and completedAt to \"2026-02-01T00:00:00.000Z\".",
150
+ "weight": 1,
151
+ "required": true
152
+ },
153
+ {
154
+ "id": "warm-medium-complete-is-idempotent",
155
+ "text": "When the task is already completed the updater returns it unchanged, so completing it again does not rewrite completedAt.",
156
+ "weight": 1,
157
+ "required": true
158
+ },
159
+ {
160
+ "id": "warm-medium-complete-unknown-task-throws",
161
+ "text": "An unknown task id throws \"Unknown task id: <id>\" from TaskWorkflowStore.updateTask.",
162
+ "weight": 1,
163
+ "required": true
164
+ }
165
+ ],
166
+ "minimumCorrectFacts": 3,
167
+ "notes": "Localized: the behavior lives in one service plus the store update primitive."
168
+ },
169
+ "rawIncludeGlobs": ["src/**/*", "tests/**/*"],
170
+ "notes": "v0.5.1 warm-index medium localized case."
171
+ },
172
+ {
173
+ "id": "warm-medium-composite-filter",
174
+ "title": "Warm-index composite task filtering",
175
+ "benchmarkProject": "task-workflow-medium-ts",
176
+ "projectProfileRef": "task-workflow-medium-ts",
177
+ "taskLocality": "cross-module",
178
+ "targetRoot": "benchmarks/projects/task-workflow-medium-ts",
179
+ "sourceRoots": ["src", "tests"],
180
+ "query": "filter tasks project completed priority tag text query ordering",
181
+ "expectedFiles": ["src/services/filterTasks.ts", "src/models/task.ts", "src/store/taskStore.ts"],
182
+ "expectedSymbols": ["filterTasks", "TaskFilter", "TaskWorkflowStore"],
183
+ "answerKey": {
184
+ "expectedFiles": ["src/services/filterTasks.ts", "src/models/task.ts", "src/store/taskStore.ts"],
185
+ "expectedSymbols": ["filterTasks", "TaskFilter", "TaskWorkflowStore"],
186
+ "expectedFacts": [
187
+ {
188
+ "id": "warm-medium-filter-combines-active-predicates",
189
+ "text": "filterTasks keeps a task only when it satisfies every supplied TaskFilter field; fields that are not supplied do not filter.",
190
+ "weight": 1,
191
+ "required": true
192
+ },
193
+ {
194
+ "id": "warm-medium-filter-project",
195
+ "text": "The projectId filter requires task.projectId to equal the requested project id.",
196
+ "weight": 1,
197
+ "required": true
198
+ },
199
+ {
200
+ "id": "warm-medium-filter-completed-priority-tag",
201
+ "text": "The completed filter compares the boolean when defined, priority must match exactly, and the tag is trimmed and lowercased before checking task.tags.",
202
+ "weight": 1,
203
+ "required": true
204
+ },
205
+ {
206
+ "id": "warm-medium-filter-text-query",
207
+ "text": "The query is trimmed and lowercased and matched as a substring of the lowercased title, notes, and tags joined with spaces.",
208
+ "weight": 1,
209
+ "required": true
210
+ },
211
+ {
212
+ "id": "warm-medium-filter-read-only-ordering",
213
+ "text": "filterTasks only reads store.listTasks(), which returns task copies sorted by task id, and returns the matches in that order without mutating the store.",
214
+ "weight": 1,
215
+ "required": true
216
+ }
217
+ ],
218
+ "minimumCorrectFacts": 4,
219
+ "notes": "Cross-module: filter semantics depend on the TaskFilter model and store listing order."
220
+ },
221
+ "rawIncludeGlobs": ["src/**/*", "tests/**/*"],
222
+ "notes": "v0.5.1 warm-index medium case for composite filtering."
223
+ },
224
+ {
225
+ "id": "warm-medium-project-summary",
226
+ "title": "Warm-index workflow project summary",
227
+ "benchmarkProject": "task-workflow-medium-ts",
228
+ "projectProfileRef": "task-workflow-medium-ts",
229
+ "taskLocality": "cross-module",
230
+ "targetRoot": "benchmarks/projects/task-workflow-medium-ts",
231
+ "sourceRoots": ["src", "tests"],
232
+ "query": "summarize tasks total open completed per project high priority open",
233
+ "expectedFiles": [
234
+ "src/services/summarizeTasks.ts",
235
+ "src/store/taskStore.ts",
236
+ "src/models/task.ts",
237
+ "src/models/project.ts"
238
+ ],
239
+ "expectedSymbols": ["summarizeTasks", "TaskSummary", "TaskWorkflowStore", "WorkflowProject"],
240
+ "answerKey": {
241
+ "expectedFiles": [
242
+ "src/services/summarizeTasks.ts",
243
+ "src/store/taskStore.ts",
244
+ "src/models/task.ts",
245
+ "src/models/project.ts"
246
+ ],
247
+ "expectedSymbols": ["summarizeTasks", "TaskSummary", "TaskWorkflowStore", "WorkflowProject"],
248
+ "expectedFacts": [
249
+ {
250
+ "id": "warm-medium-summary-total-open-completed",
251
+ "text": "summarizeTasks reports total, completed, and open counts across all tasks, where open equals total minus completed.",
252
+ "weight": 1,
253
+ "required": true
254
+ },
255
+ {
256
+ "id": "warm-medium-summary-by-project",
257
+ "text": "byProject holds total, completed, and open counts for every project returned by store.listProjects(), including zero counts for projects without tasks, plus any task projectId not registered as a project.",
258
+ "weight": 1,
259
+ "required": true
260
+ },
261
+ {
262
+ "id": "warm-medium-summary-high-priority-open",
263
+ "text": "highPriorityOpenTitles lists the titles of tasks that are not completed and have priority \"high\".",
264
+ "weight": 1,
265
+ "required": true
266
+ },
267
+ {
268
+ "id": "warm-medium-summary-read-only",
269
+ "text": "summarizeTasks reads copies from store.listTasks() and store.listProjects() and does not mutate stored tasks.",
270
+ "weight": 1,
271
+ "required": true
272
+ }
273
+ ],
274
+ "minimumCorrectFacts": 3,
275
+ "notes": "Cross-module: the summary combines the store with task and project models."
276
+ },
277
+ "rawIncludeGlobs": ["src/**/*", "tests/**/*"],
278
+ "notes": "v0.5.1 warm-index medium case for project summaries."
279
+ },
280
+ {
281
+ "id": "warm-medium-broad-workflow-map",
282
+ "title": "Warm-index broad task workflow architecture map",
283
+ "benchmarkProject": "task-workflow-medium-ts",
284
+ "projectProfileRef": "task-workflow-medium-ts",
285
+ "taskLocality": "broad-change",
286
+ "targetRoot": "benchmarks/projects/task-workflow-medium-ts",
287
+ "sourceRoots": ["src", "tests"],
288
+ "query": "explain task creation import duplicate filtering completion summary validation store workflow",
289
+ "expectedFiles": [
290
+ "src/services/createTask.ts",
291
+ "src/services/importTasks.ts",
292
+ "src/services/filterTasks.ts",
293
+ "src/services/completeTask.ts",
294
+ "src/services/summarizeTasks.ts",
295
+ "src/store/taskStore.ts",
296
+ "src/validation/taskValidation.ts"
297
+ ],
298
+ "expectedSymbols": [
299
+ "createTask",
300
+ "importTasks",
301
+ "filterTasks",
302
+ "completeTask",
303
+ "summarizeTasks",
304
+ "TaskWorkflowStore",
305
+ "validateImportInput"
306
+ ],
307
+ "answerKey": {
308
+ "expectedFiles": [
309
+ "src/services/createTask.ts",
310
+ "src/services/importTasks.ts",
311
+ "src/services/filterTasks.ts",
312
+ "src/services/completeTask.ts",
313
+ "src/services/summarizeTasks.ts",
314
+ "src/store/taskStore.ts",
315
+ "src/validation/taskValidation.ts"
316
+ ],
317
+ "expectedSymbols": [
318
+ "createTask",
319
+ "importTasks",
320
+ "filterTasks",
321
+ "completeTask",
322
+ "summarizeTasks",
323
+ "TaskWorkflowStore",
324
+ "validateImportInput"
325
+ ],
326
+ "expectedFacts": [
327
+ {
328
+ "id": "warm-medium-broad-shared-storage",
329
+ "text": "Both the createTask service and importTasks store new tasks through TaskWorkflowStore.createTask, sharing its deterministic task id sequence.",
330
+ "weight": 1,
331
+ "required": true
332
+ },
333
+ {
334
+ "id": "warm-medium-broad-import-adds-dedupe",
335
+ "text": "importTasks validates each item with validateImportInput and skips duplicates found by TaskWorkflowStore.findDuplicate (same project and normalized title), recording their ids in skippedDuplicates; plain task creation does not deduplicate.",
336
+ "weight": 1,
337
+ "required": true
338
+ },
339
+ {
340
+ "id": "warm-medium-broad-filter-read-only",
341
+ "text": "filterTasks reads store.listTasks() and returns matching tasks without changing workflow state.",
342
+ "weight": 1,
343
+ "required": true
344
+ },
345
+ {
346
+ "id": "warm-medium-broad-complete-targeted",
347
+ "text": "completeTask changes a single task by id through TaskWorkflowStore.updateTask.",
348
+ "weight": 1,
349
+ "required": true
350
+ },
351
+ {
352
+ "id": "warm-medium-broad-summary-aggregates",
353
+ "text": "summarizeTasks aggregates counts from the current tasks and projects held by the store.",
354
+ "weight": 1,
355
+ "required": true
356
+ }
357
+ ],
358
+ "forbiddenWrongClaims": ["importTasks calls the createTask service to insert imported tasks."],
359
+ "minimumCorrectFacts": 4,
360
+ "notes": "Deliberately wide-scope negative control spanning every workflow service; it is not expected to fit a small localized context."
361
+ },
362
+ "rawIncludeGlobs": ["src/**/*", "tests/**/*"],
363
+ "notes": "v0.5.1 warm-index medium broad-change negative control."
364
+ },
365
+ {
366
+ "id": "warm-large-health-label",
367
+ "title": "Warm-index task analytics health label retrieval",
368
+ "benchmarkProject": "task-analytics-large-mixed",
369
+ "projectProfileRef": "task-analytics-large-mixed",
370
+ "taskLocality": "cross-module",
371
+ "targetRoot": "benchmarks/projects/task-analytics-large-mixed",
372
+ "sourceRoots": ["ts/src", "ts/tests", "py/task_analytics", "py/tests"],
373
+ "query": "completion rate stale tasks quality label health report analytics snapshot",
374
+ "expectedFiles": [
375
+ "ts/src/services/buildAnalyticsSnapshot.ts",
376
+ "ts/src/reporting/formatTaskHealthReport.ts",
377
+ "py/task_analytics/metrics.py",
378
+ "py/task_analytics/quality.py",
379
+ "py/task_analytics/reporting.py"
380
+ ],
381
+ "expectedSymbols": [
382
+ "buildAnalyticsSnapshot",
383
+ "formatTaskHealthReport",
384
+ "calculate_project_metrics",
385
+ "determine_quality_label",
386
+ "build_health_report"
387
+ ],
388
+ "answerKey": {
389
+ "expectedFiles": [
390
+ "ts/src/services/buildAnalyticsSnapshot.ts",
391
+ "ts/src/reporting/formatTaskHealthReport.ts",
392
+ "py/task_analytics/metrics.py",
393
+ "py/task_analytics/quality.py",
394
+ "py/task_analytics/reporting.py"
395
+ ],
396
+ "expectedSymbols": [
397
+ "buildAnalyticsSnapshot",
398
+ "formatTaskHealthReport",
399
+ "calculate_project_metrics",
400
+ "determine_quality_label",
401
+ "build_health_report"
402
+ ],
403
+ "expectedFacts": [
404
+ {
405
+ "id": "warm-large-snapshot-computes-completion-rate",
406
+ "text": "The analytics snapshot computes completionRate as completedTasks divided by totalTasks times 100, rounded to two decimals.",
407
+ "weight": 1,
408
+ "required": true
409
+ },
410
+ {
411
+ "id": "warm-large-snapshot-counts-stale-open-tasks",
412
+ "text": "Stale tasks count only open tasks whose updated day is at least ten days behind the current day.",
413
+ "weight": 1,
414
+ "required": true
415
+ },
416
+ {
417
+ "id": "warm-large-python-quality-labels-healthy-watch-risk",
418
+ "text": "The Python quality layer maps metrics to healthy, watch, or risk labels based on completion rate and stale task thresholds.",
419
+ "weight": 1,
420
+ "required": true
421
+ },
422
+ {
423
+ "id": "warm-large-python-reporting-renders-quality-lines",
424
+ "text": "The Python report writer emits one line per project with the quality label plus completion, open, and stale counts.",
425
+ "weight": 1,
426
+ "required": true
427
+ }
428
+ ],
429
+ "minimumCorrectFacts": 3,
430
+ "notes": "Cross-module retrieval spanning TypeScript snapshot building and Python quality reporting."
431
+ },
432
+ "rawIncludeGlobs": ["ts/src/**/*", "ts/tests/**/*", "py/task_analytics/**/*", "py/tests/**/*"],
433
+ "notes": "v0.5.1 warm-index seed case grounded in the existing task-analytics-health-label behavior."
434
+ },
435
+ {
436
+ "id": "warm-large-ts-analytics-snapshot",
437
+ "title": "Warm-index TypeScript analytics snapshot",
438
+ "benchmarkProject": "task-analytics-large-mixed",
439
+ "projectProfileRef": "task-analytics-large-mixed",
440
+ "taskLocality": "cross-module",
441
+ "targetRoot": "benchmarks/projects/task-analytics-large-mixed",
442
+ "sourceRoots": ["ts/src", "ts/tests", "py/task_analytics", "py/tests"],
443
+ "query": "analytics snapshot project completion rate stale tasks average story points task store",
444
+ "expectedFiles": [
445
+ "ts/src/services/buildAnalyticsSnapshot.ts",
446
+ "ts/src/services/listTasksByProject.ts",
447
+ "ts/src/models/analyticsSnapshot.ts",
448
+ "ts/src/store/taskStore.ts"
449
+ ],
450
+ "expectedSymbols": ["buildAnalyticsSnapshot", "listTasksByProject", "ProjectSnapshot", "AnalyticsTaskStore"],
451
+ "answerKey": {
452
+ "expectedFiles": [
453
+ "ts/src/services/buildAnalyticsSnapshot.ts",
454
+ "ts/src/services/listTasksByProject.ts",
455
+ "ts/src/models/analyticsSnapshot.ts",
456
+ "ts/src/store/taskStore.ts"
457
+ ],
458
+ "expectedSymbols": ["buildAnalyticsSnapshot", "listTasksByProject", "ProjectSnapshot", "AnalyticsTaskStore"],
459
+ "expectedFacts": [
460
+ {
461
+ "id": "warm-large-snapshot-per-project-counts",
462
+ "text": "For each project from ProjectStore.list(), buildAnalyticsSnapshot loads the project's tasks with listTasksByProject (AnalyticsTaskStore.list() filtered by projectId) and records totalTasks, completedTasks, and openTasks as totalTasks minus completedTasks.",
463
+ "weight": 1,
464
+ "required": true
465
+ },
466
+ {
467
+ "id": "warm-large-snapshot-completion-rate-formula",
468
+ "text": "completionRate is completedTasks divided by totalTasks times 100, rounded to two decimals with Math.round(value * 100) / 100.",
469
+ "weight": 1,
470
+ "required": true
471
+ },
472
+ {
473
+ "id": "warm-large-snapshot-stale-condition",
474
+ "text": "staleTasks counts only incomplete tasks whose currentDay minus updatedDay is at least STALE_DAY_THRESHOLD (10).",
475
+ "weight": 1,
476
+ "required": true
477
+ },
478
+ {
479
+ "id": "warm-large-snapshot-empty-project",
480
+ "text": "A project with no tasks gets zero counts, completionRate 0, and averageStoryPoints 0; otherwise averageStoryPoints is the mean story points rounded to two decimals.",
481
+ "weight": 1,
482
+ "required": true
483
+ },
484
+ {
485
+ "id": "warm-large-snapshot-totals-aggregate",
486
+ "text": "The snapshot totals sum totalTasks, completedTasks, openTasks, and staleTasks across the per-project snapshots.",
487
+ "weight": 1,
488
+ "required": true
489
+ }
490
+ ],
491
+ "minimumCorrectFacts": 4,
492
+ "notes": "Cross-module: the snapshot service composes the task-listing service, the task store, and the snapshot model."
493
+ },
494
+ "rawIncludeGlobs": ["ts/src/**/*", "ts/tests/**/*", "py/task_analytics/**/*", "py/tests/**/*"],
495
+ "notes": "v0.5.1 warm-index large case for the TypeScript analytics snapshot."
496
+ },
497
+ {
498
+ "id": "warm-large-ts-leaderboard",
499
+ "title": "Warm-index deterministic project leaderboard",
500
+ "benchmarkProject": "task-analytics-large-mixed",
501
+ "projectProfileRef": "task-analytics-large-mixed",
502
+ "taskLocality": "localized",
503
+ "targetRoot": "benchmarks/projects/task-analytics-large-mixed",
504
+ "sourceRoots": ["ts/src", "ts/tests", "py/task_analytics", "py/tests"],
505
+ "query": "project leaderboard completion rate stale tasks tie break project id ranking",
506
+ "expectedFiles": ["ts/src/reporting/buildProjectLeaderboard.ts", "ts/src/models/analyticsSnapshot.ts"],
507
+ "expectedSymbols": ["buildProjectLeaderboard", "ProjectSnapshot"],
508
+ "answerKey": {
509
+ "expectedFiles": ["ts/src/reporting/buildProjectLeaderboard.ts", "ts/src/models/analyticsSnapshot.ts"],
510
+ "expectedSymbols": ["buildProjectLeaderboard", "ProjectSnapshot"],
511
+ "expectedFacts": [
512
+ {
513
+ "id": "warm-large-leaderboard-completion-rate-descending",
514
+ "text": "buildProjectLeaderboard sorts a copy of snapshot.projects by completionRate in descending order.",
515
+ "weight": 1,
516
+ "required": true
517
+ },
518
+ {
519
+ "id": "warm-large-leaderboard-stale-ascending",
520
+ "text": "Ties on completionRate are broken by staleTasks in ascending order.",
521
+ "weight": 1,
522
+ "required": true
523
+ },
524
+ {
525
+ "id": "warm-large-leaderboard-project-id-final",
526
+ "text": "Remaining ties are broken by projectId in ascending localeCompare order.",
527
+ "weight": 1,
528
+ "required": true
529
+ },
530
+ {
531
+ "id": "warm-large-leaderboard-one-based-ranks",
532
+ "text": "Each line is formatted as \"<rank>. <projectId> (<completionRate>% complete, <staleTasks> stale)\" with ranks starting at 1.",
533
+ "weight": 1,
534
+ "required": true
535
+ }
536
+ ],
537
+ "minimumCorrectFacts": 3,
538
+ "notes": "Localized: the ranking rule lives in one reporting function over the ProjectSnapshot model."
539
+ },
540
+ "rawIncludeGlobs": ["ts/src/**/*", "ts/tests/**/*", "py/task_analytics/**/*", "py/tests/**/*"],
541
+ "notes": "v0.5.1 warm-index large localized case."
542
+ },
543
+ {
544
+ "id": "warm-large-python-parser-metrics",
545
+ "title": "Warm-index Python parser and project metrics",
546
+ "benchmarkProject": "task-analytics-large-mixed",
547
+ "projectProfileRef": "task-analytics-large-mixed",
548
+ "taskLocality": "cross-module",
549
+ "targetRoot": "benchmarks/projects/task-analytics-large-mixed",
550
+ "sourceRoots": ["ts/src", "ts/tests", "py/task_analytics", "py/tests"],
551
+ "query": "parse task rows calculate project metrics completion open stale story points",
552
+ "expectedFiles": ["py/task_analytics/parser.py", "py/task_analytics/models.py", "py/task_analytics/metrics.py"],
553
+ "expectedSymbols": ["parse_task_rows", "TaskRecord", "calculate_project_metrics", "ProjectMetrics"],
554
+ "answerKey": {
555
+ "expectedFiles": ["py/task_analytics/parser.py", "py/task_analytics/models.py", "py/task_analytics/metrics.py"],
556
+ "expectedSymbols": ["parse_task_rows", "TaskRecord", "calculate_project_metrics", "ProjectMetrics"],
557
+ "expectedFacts": [
558
+ {
559
+ "id": "warm-large-python-parser-task-record",
560
+ "text": "parse_task_rows converts each row into a TaskRecord with task_id and project_id as str, completed as bool, and story_points and updated_day as int.",
561
+ "weight": 1,
562
+ "required": true
563
+ },
564
+ {
565
+ "id": "warm-large-python-metrics-grouped-by-project",
566
+ "text": "calculate_project_metrics groups tasks by project_id and returns one ProjectMetrics per project in sorted project_id order.",
567
+ "weight": 1,
568
+ "required": true
569
+ },
570
+ {
571
+ "id": "warm-large-python-metrics-counts",
572
+ "text": "open_tasks is total_tasks minus completed_tasks, and stale_tasks counts incomplete tasks whose current_day minus updated_day is at least STALE_DAY_THRESHOLD (10).",
573
+ "weight": 1,
574
+ "required": true
575
+ },
576
+ {
577
+ "id": "warm-large-python-metrics-completion-rate",
578
+ "text": "completion_rate is round((completed / total) * 100, 2), or 0.0 when a project has no tasks.",
579
+ "weight": 1,
580
+ "required": true
581
+ },
582
+ {
583
+ "id": "warm-large-python-metrics-average-story-points",
584
+ "text": "average_story_points is the mean story_points rounded with round(..., 2), or 0.0 when a project has no tasks.",
585
+ "weight": 1,
586
+ "required": true
587
+ }
588
+ ],
589
+ "minimumCorrectFacts": 4,
590
+ "notes": "Cross-module: parsing, the record models, and metric calculation live in separate Python modules."
591
+ },
592
+ "rawIncludeGlobs": ["ts/src/**/*", "ts/tests/**/*", "py/task_analytics/**/*", "py/tests/**/*"],
593
+ "notes": "v0.5.1 warm-index large case for Python parsing and metrics."
594
+ },
595
+ {
596
+ "id": "warm-large-python-pipeline",
597
+ "title": "Warm-index Python analytics report pipeline",
598
+ "benchmarkProject": "task-analytics-large-mixed",
599
+ "projectProfileRef": "task-analytics-large-mixed",
600
+ "taskLocality": "cross-module",
601
+ "targetRoot": "benchmarks/projects/task-analytics-large-mixed",
602
+ "sourceRoots": ["ts/src", "ts/tests", "py/task_analytics", "py/tests"],
603
+ "query": "pipeline parse rows project metrics quality label health report",
604
+ "expectedFiles": [
605
+ "py/task_analytics/pipeline.py",
606
+ "py/task_analytics/parser.py",
607
+ "py/task_analytics/metrics.py",
608
+ "py/task_analytics/quality.py",
609
+ "py/task_analytics/reporting.py"
610
+ ],
611
+ "expectedSymbols": [
612
+ "build_report_from_rows",
613
+ "parse_task_rows",
614
+ "calculate_project_metrics",
615
+ "determine_quality_label",
616
+ "build_health_report"
617
+ ],
618
+ "answerKey": {
619
+ "expectedFiles": [
620
+ "py/task_analytics/pipeline.py",
621
+ "py/task_analytics/parser.py",
622
+ "py/task_analytics/metrics.py",
623
+ "py/task_analytics/quality.py",
624
+ "py/task_analytics/reporting.py"
625
+ ],
626
+ "expectedSymbols": [
627
+ "build_report_from_rows",
628
+ "parse_task_rows",
629
+ "calculate_project_metrics",
630
+ "determine_quality_label",
631
+ "build_health_report"
632
+ ],
633
+ "expectedFacts": [
634
+ {
635
+ "id": "warm-large-pipeline-parses-first",
636
+ "text": "build_report_from_rows(rows, current_day) first parses the rows with parse_task_rows.",
637
+ "weight": 1,
638
+ "required": true
639
+ },
640
+ {
641
+ "id": "warm-large-pipeline-metrics-before-report",
642
+ "text": "The parsed tasks go to calculate_project_metrics(tasks, current_day), and the resulting metrics go to build_health_report.",
643
+ "weight": 1,
644
+ "required": true
645
+ },
646
+ {
647
+ "id": "warm-large-pipeline-quality-label-in-report",
648
+ "text": "build_health_report calls determine_quality_label for each metric, which returns empty, healthy, watch, or risk from total_tasks, completion_rate, and stale_tasks thresholds.",
649
+ "weight": 1,
650
+ "required": true
651
+ },
652
+ {
653
+ "id": "warm-large-pipeline-deterministic-output",
654
+ "text": "The report is one line per project, \"<project_id>: <label> | completion=<rate>% | open=<n> | stale=<n>\", joined by newlines in sorted project_id order, so fixed rows and current_day produce the same output.",
655
+ "weight": 1,
656
+ "required": true
657
+ },
658
+ {
659
+ "id": "warm-large-pipeline-composes-owners",
660
+ "text": "pipeline.py only composes parse_task_rows, calculate_project_metrics, and build_health_report; quality rules stay in quality.py and are reached through reporting.",
661
+ "weight": 1,
662
+ "required": true
663
+ }
664
+ ],
665
+ "minimumCorrectFacts": 4,
666
+ "notes": "Cross-module: the pipeline composes parser, metrics, reporting, and (through reporting) quality modules."
667
+ },
668
+ "rawIncludeGlobs": ["ts/src/**/*", "ts/tests/**/*", "py/task_analytics/**/*", "py/tests/**/*"],
669
+ "notes": "v0.5.1 warm-index large case for the Python report pipeline."
670
+ },
671
+ {
672
+ "id": "warm-large-broad-analytics-comparison",
673
+ "title": "Warm-index broad TypeScript and Python analytics comparison",
674
+ "benchmarkProject": "task-analytics-large-mixed",
675
+ "projectProfileRef": "task-analytics-large-mixed",
676
+ "taskLocality": "broad-change",
677
+ "targetRoot": "benchmarks/projects/task-analytics-large-mixed",
678
+ "sourceRoots": ["ts/src", "ts/tests", "py/task_analytics", "py/tests"],
679
+ "query": "compare TypeScript and Python project analytics snapshot metrics quality reporting pipeline leaderboard",
680
+ "expectedFiles": [
681
+ "ts/src/services/buildAnalyticsSnapshot.ts",
682
+ "ts/src/reporting/formatTaskHealthReport.ts",
683
+ "ts/src/reporting/buildProjectLeaderboard.ts",
684
+ "py/task_analytics/parser.py",
685
+ "py/task_analytics/metrics.py",
686
+ "py/task_analytics/quality.py",
687
+ "py/task_analytics/reporting.py",
688
+ "py/task_analytics/pipeline.py"
689
+ ],
690
+ "expectedSymbols": [
691
+ "buildAnalyticsSnapshot",
692
+ "formatTaskHealthReport",
693
+ "buildProjectLeaderboard",
694
+ "parse_task_rows",
695
+ "calculate_project_metrics",
696
+ "determine_quality_label",
697
+ "build_health_report",
698
+ "build_report_from_rows"
699
+ ],
700
+ "answerKey": {
701
+ "expectedFiles": [
702
+ "ts/src/services/buildAnalyticsSnapshot.ts",
703
+ "ts/src/reporting/formatTaskHealthReport.ts",
704
+ "ts/src/reporting/buildProjectLeaderboard.ts",
705
+ "py/task_analytics/parser.py",
706
+ "py/task_analytics/metrics.py",
707
+ "py/task_analytics/quality.py",
708
+ "py/task_analytics/reporting.py",
709
+ "py/task_analytics/pipeline.py"
710
+ ],
711
+ "expectedSymbols": [
712
+ "buildAnalyticsSnapshot",
713
+ "formatTaskHealthReport",
714
+ "buildProjectLeaderboard",
715
+ "parse_task_rows",
716
+ "calculate_project_metrics",
717
+ "determine_quality_label",
718
+ "build_health_report",
719
+ "build_report_from_rows"
720
+ ],
721
+ "expectedFacts": [
722
+ {
723
+ "id": "warm-large-broad-typescript-side",
724
+ "text": "The TypeScript side builds analytics snapshots with buildAnalyticsSnapshot and presents them through formatTaskHealthReport, which uses buildProjectLeaderboard for ranking.",
725
+ "weight": 1,
726
+ "required": true
727
+ },
728
+ {
729
+ "id": "warm-large-broad-python-side",
730
+ "text": "The Python side parses rows (parse_task_rows), derives project metrics (calculate_project_metrics), assigns quality labels (determine_quality_label), and builds reports (build_health_report), composed by build_report_from_rows.",
731
+ "weight": 1,
732
+ "required": true
733
+ },
734
+ {
735
+ "id": "warm-large-broad-comparable-evidence",
736
+ "text": "Both sides expose comparable per-project health evidence: total, completed, open, and stale task counts plus a completion rate rounded to two decimals, using a stale threshold of 10 days.",
737
+ "weight": 1,
738
+ "required": true
739
+ },
740
+ {
741
+ "id": "warm-large-broad-independent-implementations",
742
+ "text": "The TypeScript and Python code are independent parallel benchmark implementations, not a runtime TypeScript-to-Python call chain.",
743
+ "weight": 1,
744
+ "required": true
745
+ },
746
+ {
747
+ "id": "warm-large-broad-no-cross-invocation",
748
+ "text": "Neither implementation imports, spawns, or calls the other; TypeScript imports stay within ts/src and Python imports stay within the task_analytics package.",
749
+ "weight": 1,
750
+ "required": true
751
+ }
752
+ ],
753
+ "forbiddenWrongClaims": [
754
+ "The TypeScript implementation invokes the Python analytics pipeline.",
755
+ "Python is a runtime backend for the TypeScript analytics implementation.",
756
+ "The TypeScript or Python implementation directly imports or calls the other."
757
+ ],
758
+ "minimumCorrectFacts": 4,
759
+ "notes": "Deliberately wide-scope negative control spanning both language implementations; it is not expected to fit a small localized context."
760
+ },
761
+ "rawIncludeGlobs": ["ts/src/**/*", "ts/tests/**/*", "py/task_analytics/**/*", "py/tests/**/*"],
762
+ "notes": "v0.5.1 warm-index large broad-change negative control."
763
+ }
764
+ ]