@aida-dev/metrics 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +618 -26
- package/dist/index.js +213 -28
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,196 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Commit, CommitStream } from '@aida-dev/core';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
|
+
declare const Attribution: z.ZodObject<{
|
|
5
|
+
commitsTotal: z.ZodNumber;
|
|
6
|
+
ai: z.ZodNumber;
|
|
7
|
+
human: z.ZodNumber;
|
|
8
|
+
unknown: z.ZodNumber;
|
|
9
|
+
coverage: z.ZodNumber;
|
|
10
|
+
defaultAttribution: z.ZodEnum<["ai", "human", "unknown"]>;
|
|
11
|
+
coverageThreshold: z.ZodNumber;
|
|
12
|
+
belowThreshold: z.ZodBoolean;
|
|
13
|
+
modes: z.ZodObject<{
|
|
14
|
+
none: z.ZodNumber;
|
|
15
|
+
autocomplete: z.ZodNumber;
|
|
16
|
+
assisted: z.ZodNumber;
|
|
17
|
+
agent: z.ZodNumber;
|
|
18
|
+
unknown: z.ZodNumber;
|
|
19
|
+
}, "strip", z.ZodTypeAny, {
|
|
20
|
+
unknown: number;
|
|
21
|
+
none: number;
|
|
22
|
+
autocomplete: number;
|
|
23
|
+
assisted: number;
|
|
24
|
+
agent: number;
|
|
25
|
+
}, {
|
|
26
|
+
unknown: number;
|
|
27
|
+
none: number;
|
|
28
|
+
autocomplete: number;
|
|
29
|
+
assisted: number;
|
|
30
|
+
agent: number;
|
|
31
|
+
}>;
|
|
32
|
+
modeEvidence: z.ZodObject<{
|
|
33
|
+
declared: z.ZodNumber;
|
|
34
|
+
inferred: z.ZodNumber;
|
|
35
|
+
none: z.ZodNumber;
|
|
36
|
+
}, "strip", z.ZodTypeAny, {
|
|
37
|
+
none: number;
|
|
38
|
+
declared: number;
|
|
39
|
+
inferred: number;
|
|
40
|
+
}, {
|
|
41
|
+
none: number;
|
|
42
|
+
declared: number;
|
|
43
|
+
inferred: number;
|
|
44
|
+
}>;
|
|
45
|
+
}, "strip", z.ZodTypeAny, {
|
|
46
|
+
ai: number;
|
|
47
|
+
human: number;
|
|
48
|
+
unknown: number;
|
|
49
|
+
commitsTotal: number;
|
|
50
|
+
coverage: number;
|
|
51
|
+
defaultAttribution: "ai" | "human" | "unknown";
|
|
52
|
+
coverageThreshold: number;
|
|
53
|
+
belowThreshold: boolean;
|
|
54
|
+
modes: {
|
|
55
|
+
unknown: number;
|
|
56
|
+
none: number;
|
|
57
|
+
autocomplete: number;
|
|
58
|
+
assisted: number;
|
|
59
|
+
agent: number;
|
|
60
|
+
};
|
|
61
|
+
modeEvidence: {
|
|
62
|
+
none: number;
|
|
63
|
+
declared: number;
|
|
64
|
+
inferred: number;
|
|
65
|
+
};
|
|
66
|
+
}, {
|
|
67
|
+
ai: number;
|
|
68
|
+
human: number;
|
|
69
|
+
unknown: number;
|
|
70
|
+
commitsTotal: number;
|
|
71
|
+
coverage: number;
|
|
72
|
+
defaultAttribution: "ai" | "human" | "unknown";
|
|
73
|
+
coverageThreshold: number;
|
|
74
|
+
belowThreshold: boolean;
|
|
75
|
+
modes: {
|
|
76
|
+
unknown: number;
|
|
77
|
+
none: number;
|
|
78
|
+
autocomplete: number;
|
|
79
|
+
assisted: number;
|
|
80
|
+
agent: number;
|
|
81
|
+
};
|
|
82
|
+
modeEvidence: {
|
|
83
|
+
none: number;
|
|
84
|
+
declared: number;
|
|
85
|
+
inferred: number;
|
|
86
|
+
};
|
|
87
|
+
}>;
|
|
88
|
+
type Attribution = z.infer<typeof Attribution>;
|
|
89
|
+
declare const AgeStats: z.ZodObject<{
|
|
90
|
+
commits: z.ZodNumber;
|
|
91
|
+
avgAgeDays: z.ZodNumber;
|
|
92
|
+
medianAgeDays: z.ZodNumber;
|
|
93
|
+
}, "strip", z.ZodTypeAny, {
|
|
94
|
+
commits: number;
|
|
95
|
+
avgAgeDays: number;
|
|
96
|
+
medianAgeDays: number;
|
|
97
|
+
}, {
|
|
98
|
+
commits: number;
|
|
99
|
+
avgAgeDays: number;
|
|
100
|
+
medianAgeDays: number;
|
|
101
|
+
}>;
|
|
102
|
+
type AgeStats = z.infer<typeof AgeStats>;
|
|
103
|
+
declare const FileCategory: z.ZodEnum<["source", "tests", "migrations", "config", "docs", "generated"]>;
|
|
104
|
+
type FileCategory = z.infer<typeof FileCategory>;
|
|
105
|
+
declare const CategoryCounts: z.ZodObject<{
|
|
106
|
+
source: z.ZodNumber;
|
|
107
|
+
tests: z.ZodNumber;
|
|
108
|
+
migrations: z.ZodNumber;
|
|
109
|
+
config: z.ZodNumber;
|
|
110
|
+
docs: z.ZodNumber;
|
|
111
|
+
generated: z.ZodNumber;
|
|
112
|
+
}, "strip", z.ZodTypeAny, {
|
|
113
|
+
source: number;
|
|
114
|
+
tests: number;
|
|
115
|
+
migrations: number;
|
|
116
|
+
config: number;
|
|
117
|
+
docs: number;
|
|
118
|
+
generated: number;
|
|
119
|
+
}, {
|
|
120
|
+
source: number;
|
|
121
|
+
tests: number;
|
|
122
|
+
migrations: number;
|
|
123
|
+
config: number;
|
|
124
|
+
docs: number;
|
|
125
|
+
generated: number;
|
|
126
|
+
}>;
|
|
127
|
+
type CategoryCounts = z.infer<typeof CategoryCounts>;
|
|
128
|
+
declare const CohortContext: z.ZodObject<{
|
|
129
|
+
age: z.ZodNullable<z.ZodObject<{
|
|
130
|
+
commits: z.ZodNumber;
|
|
131
|
+
avgAgeDays: z.ZodNumber;
|
|
132
|
+
medianAgeDays: z.ZodNumber;
|
|
133
|
+
}, "strip", z.ZodTypeAny, {
|
|
134
|
+
commits: number;
|
|
135
|
+
avgAgeDays: number;
|
|
136
|
+
medianAgeDays: number;
|
|
137
|
+
}, {
|
|
138
|
+
commits: number;
|
|
139
|
+
avgAgeDays: number;
|
|
140
|
+
medianAgeDays: number;
|
|
141
|
+
}>>;
|
|
142
|
+
taskMix: z.ZodNullable<z.ZodObject<{
|
|
143
|
+
source: z.ZodNumber;
|
|
144
|
+
tests: z.ZodNumber;
|
|
145
|
+
migrations: z.ZodNumber;
|
|
146
|
+
config: z.ZodNumber;
|
|
147
|
+
docs: z.ZodNumber;
|
|
148
|
+
generated: z.ZodNumber;
|
|
149
|
+
}, "strip", z.ZodTypeAny, {
|
|
150
|
+
source: number;
|
|
151
|
+
tests: number;
|
|
152
|
+
migrations: number;
|
|
153
|
+
config: number;
|
|
154
|
+
docs: number;
|
|
155
|
+
generated: number;
|
|
156
|
+
}, {
|
|
157
|
+
source: number;
|
|
158
|
+
tests: number;
|
|
159
|
+
migrations: number;
|
|
160
|
+
config: number;
|
|
161
|
+
docs: number;
|
|
162
|
+
generated: number;
|
|
163
|
+
}>>;
|
|
164
|
+
}, "strip", z.ZodTypeAny, {
|
|
165
|
+
age: {
|
|
166
|
+
commits: number;
|
|
167
|
+
avgAgeDays: number;
|
|
168
|
+
medianAgeDays: number;
|
|
169
|
+
} | null;
|
|
170
|
+
taskMix: {
|
|
171
|
+
source: number;
|
|
172
|
+
tests: number;
|
|
173
|
+
migrations: number;
|
|
174
|
+
config: number;
|
|
175
|
+
docs: number;
|
|
176
|
+
generated: number;
|
|
177
|
+
} | null;
|
|
178
|
+
}, {
|
|
179
|
+
age: {
|
|
180
|
+
commits: number;
|
|
181
|
+
avgAgeDays: number;
|
|
182
|
+
medianAgeDays: number;
|
|
183
|
+
} | null;
|
|
184
|
+
taskMix: {
|
|
185
|
+
source: number;
|
|
186
|
+
tests: number;
|
|
187
|
+
migrations: number;
|
|
188
|
+
config: number;
|
|
189
|
+
docs: number;
|
|
190
|
+
generated: number;
|
|
191
|
+
} | null;
|
|
192
|
+
}>;
|
|
193
|
+
type CohortContext = z.infer<typeof CohortContext>;
|
|
4
194
|
declare const MergeRatio: z.ZodObject<{
|
|
5
195
|
aiCommitsTotal: z.ZodNumber;
|
|
6
196
|
aiCommitsMerged: z.ZodNumber;
|
|
@@ -67,27 +257,28 @@ declare const CohortMergeRatio: z.ZodObject<{
|
|
|
67
257
|
commitsMerged: z.ZodNumber;
|
|
68
258
|
mergeRatio: z.ZodNumber;
|
|
69
259
|
}, "strip", z.ZodTypeAny, {
|
|
70
|
-
mergeRatio: number;
|
|
71
260
|
commitsTotal: number;
|
|
261
|
+
mergeRatio: number;
|
|
72
262
|
commitsMerged: number;
|
|
73
263
|
}, {
|
|
74
|
-
mergeRatio: number;
|
|
75
264
|
commitsTotal: number;
|
|
265
|
+
mergeRatio: number;
|
|
76
266
|
commitsMerged: number;
|
|
77
267
|
}>;
|
|
78
268
|
type CohortMergeRatio = z.infer<typeof CohortMergeRatio>;
|
|
79
269
|
declare const Baseline: z.ZodObject<{
|
|
270
|
+
assumed: z.ZodBoolean;
|
|
80
271
|
mergeRatio: z.ZodObject<{
|
|
81
272
|
commitsTotal: z.ZodNumber;
|
|
82
273
|
commitsMerged: z.ZodNumber;
|
|
83
274
|
mergeRatio: z.ZodNumber;
|
|
84
275
|
}, "strip", z.ZodTypeAny, {
|
|
85
|
-
mergeRatio: number;
|
|
86
276
|
commitsTotal: number;
|
|
277
|
+
mergeRatio: number;
|
|
87
278
|
commitsMerged: number;
|
|
88
279
|
}, {
|
|
89
|
-
mergeRatio: number;
|
|
90
280
|
commitsTotal: number;
|
|
281
|
+
mergeRatio: number;
|
|
91
282
|
commitsMerged: number;
|
|
92
283
|
}>;
|
|
93
284
|
persistence: z.ZodObject<{
|
|
@@ -138,8 +329,8 @@ declare const Baseline: z.ZodObject<{
|
|
|
138
329
|
}>;
|
|
139
330
|
}, "strip", z.ZodTypeAny, {
|
|
140
331
|
mergeRatio: {
|
|
141
|
-
mergeRatio: number;
|
|
142
332
|
commitsTotal: number;
|
|
333
|
+
mergeRatio: number;
|
|
143
334
|
commitsMerged: number;
|
|
144
335
|
};
|
|
145
336
|
persistence: {
|
|
@@ -154,10 +345,11 @@ declare const Baseline: z.ZodObject<{
|
|
|
154
345
|
d90_plus: number;
|
|
155
346
|
};
|
|
156
347
|
};
|
|
348
|
+
assumed: boolean;
|
|
157
349
|
}, {
|
|
158
350
|
mergeRatio: {
|
|
159
|
-
mergeRatio: number;
|
|
160
351
|
commitsTotal: number;
|
|
352
|
+
mergeRatio: number;
|
|
161
353
|
commitsMerged: number;
|
|
162
354
|
};
|
|
163
355
|
persistence: {
|
|
@@ -172,6 +364,7 @@ declare const Baseline: z.ZodObject<{
|
|
|
172
364
|
d90_plus: number;
|
|
173
365
|
};
|
|
174
366
|
};
|
|
367
|
+
assumed: boolean;
|
|
175
368
|
}>;
|
|
176
369
|
type Baseline = z.infer<typeof Baseline>;
|
|
177
370
|
declare const Delta: z.ZodObject<{
|
|
@@ -202,6 +395,90 @@ declare const Metrics: z.ZodObject<{
|
|
|
202
395
|
}>;
|
|
203
396
|
repoPath: z.ZodString;
|
|
204
397
|
defaultBranch: z.ZodString;
|
|
398
|
+
attribution: z.ZodObject<{
|
|
399
|
+
commitsTotal: z.ZodNumber;
|
|
400
|
+
ai: z.ZodNumber;
|
|
401
|
+
human: z.ZodNumber;
|
|
402
|
+
unknown: z.ZodNumber;
|
|
403
|
+
coverage: z.ZodNumber;
|
|
404
|
+
defaultAttribution: z.ZodEnum<["ai", "human", "unknown"]>;
|
|
405
|
+
coverageThreshold: z.ZodNumber;
|
|
406
|
+
belowThreshold: z.ZodBoolean;
|
|
407
|
+
modes: z.ZodObject<{
|
|
408
|
+
none: z.ZodNumber;
|
|
409
|
+
autocomplete: z.ZodNumber;
|
|
410
|
+
assisted: z.ZodNumber;
|
|
411
|
+
agent: z.ZodNumber;
|
|
412
|
+
unknown: z.ZodNumber;
|
|
413
|
+
}, "strip", z.ZodTypeAny, {
|
|
414
|
+
unknown: number;
|
|
415
|
+
none: number;
|
|
416
|
+
autocomplete: number;
|
|
417
|
+
assisted: number;
|
|
418
|
+
agent: number;
|
|
419
|
+
}, {
|
|
420
|
+
unknown: number;
|
|
421
|
+
none: number;
|
|
422
|
+
autocomplete: number;
|
|
423
|
+
assisted: number;
|
|
424
|
+
agent: number;
|
|
425
|
+
}>;
|
|
426
|
+
modeEvidence: z.ZodObject<{
|
|
427
|
+
declared: z.ZodNumber;
|
|
428
|
+
inferred: z.ZodNumber;
|
|
429
|
+
none: z.ZodNumber;
|
|
430
|
+
}, "strip", z.ZodTypeAny, {
|
|
431
|
+
none: number;
|
|
432
|
+
declared: number;
|
|
433
|
+
inferred: number;
|
|
434
|
+
}, {
|
|
435
|
+
none: number;
|
|
436
|
+
declared: number;
|
|
437
|
+
inferred: number;
|
|
438
|
+
}>;
|
|
439
|
+
}, "strip", z.ZodTypeAny, {
|
|
440
|
+
ai: number;
|
|
441
|
+
human: number;
|
|
442
|
+
unknown: number;
|
|
443
|
+
commitsTotal: number;
|
|
444
|
+
coverage: number;
|
|
445
|
+
defaultAttribution: "ai" | "human" | "unknown";
|
|
446
|
+
coverageThreshold: number;
|
|
447
|
+
belowThreshold: boolean;
|
|
448
|
+
modes: {
|
|
449
|
+
unknown: number;
|
|
450
|
+
none: number;
|
|
451
|
+
autocomplete: number;
|
|
452
|
+
assisted: number;
|
|
453
|
+
agent: number;
|
|
454
|
+
};
|
|
455
|
+
modeEvidence: {
|
|
456
|
+
none: number;
|
|
457
|
+
declared: number;
|
|
458
|
+
inferred: number;
|
|
459
|
+
};
|
|
460
|
+
}, {
|
|
461
|
+
ai: number;
|
|
462
|
+
human: number;
|
|
463
|
+
unknown: number;
|
|
464
|
+
commitsTotal: number;
|
|
465
|
+
coverage: number;
|
|
466
|
+
defaultAttribution: "ai" | "human" | "unknown";
|
|
467
|
+
coverageThreshold: number;
|
|
468
|
+
belowThreshold: boolean;
|
|
469
|
+
modes: {
|
|
470
|
+
unknown: number;
|
|
471
|
+
none: number;
|
|
472
|
+
autocomplete: number;
|
|
473
|
+
assisted: number;
|
|
474
|
+
agent: number;
|
|
475
|
+
};
|
|
476
|
+
modeEvidence: {
|
|
477
|
+
none: number;
|
|
478
|
+
declared: number;
|
|
479
|
+
inferred: number;
|
|
480
|
+
};
|
|
481
|
+
}>;
|
|
205
482
|
mergeRatio: z.ZodObject<{
|
|
206
483
|
aiCommitsTotal: z.ZodNumber;
|
|
207
484
|
aiCommitsMerged: z.ZodNumber;
|
|
@@ -261,18 +538,213 @@ declare const Metrics: z.ZodObject<{
|
|
|
261
538
|
d90_plus: number;
|
|
262
539
|
};
|
|
263
540
|
}>;
|
|
264
|
-
|
|
541
|
+
cohorts: z.ZodObject<{
|
|
542
|
+
ai: z.ZodObject<{
|
|
543
|
+
age: z.ZodNullable<z.ZodObject<{
|
|
544
|
+
commits: z.ZodNumber;
|
|
545
|
+
avgAgeDays: z.ZodNumber;
|
|
546
|
+
medianAgeDays: z.ZodNumber;
|
|
547
|
+
}, "strip", z.ZodTypeAny, {
|
|
548
|
+
commits: number;
|
|
549
|
+
avgAgeDays: number;
|
|
550
|
+
medianAgeDays: number;
|
|
551
|
+
}, {
|
|
552
|
+
commits: number;
|
|
553
|
+
avgAgeDays: number;
|
|
554
|
+
medianAgeDays: number;
|
|
555
|
+
}>>;
|
|
556
|
+
taskMix: z.ZodNullable<z.ZodObject<{
|
|
557
|
+
source: z.ZodNumber;
|
|
558
|
+
tests: z.ZodNumber;
|
|
559
|
+
migrations: z.ZodNumber;
|
|
560
|
+
config: z.ZodNumber;
|
|
561
|
+
docs: z.ZodNumber;
|
|
562
|
+
generated: z.ZodNumber;
|
|
563
|
+
}, "strip", z.ZodTypeAny, {
|
|
564
|
+
source: number;
|
|
565
|
+
tests: number;
|
|
566
|
+
migrations: number;
|
|
567
|
+
config: number;
|
|
568
|
+
docs: number;
|
|
569
|
+
generated: number;
|
|
570
|
+
}, {
|
|
571
|
+
source: number;
|
|
572
|
+
tests: number;
|
|
573
|
+
migrations: number;
|
|
574
|
+
config: number;
|
|
575
|
+
docs: number;
|
|
576
|
+
generated: number;
|
|
577
|
+
}>>;
|
|
578
|
+
}, "strip", z.ZodTypeAny, {
|
|
579
|
+
age: {
|
|
580
|
+
commits: number;
|
|
581
|
+
avgAgeDays: number;
|
|
582
|
+
medianAgeDays: number;
|
|
583
|
+
} | null;
|
|
584
|
+
taskMix: {
|
|
585
|
+
source: number;
|
|
586
|
+
tests: number;
|
|
587
|
+
migrations: number;
|
|
588
|
+
config: number;
|
|
589
|
+
docs: number;
|
|
590
|
+
generated: number;
|
|
591
|
+
} | null;
|
|
592
|
+
}, {
|
|
593
|
+
age: {
|
|
594
|
+
commits: number;
|
|
595
|
+
avgAgeDays: number;
|
|
596
|
+
medianAgeDays: number;
|
|
597
|
+
} | null;
|
|
598
|
+
taskMix: {
|
|
599
|
+
source: number;
|
|
600
|
+
tests: number;
|
|
601
|
+
migrations: number;
|
|
602
|
+
config: number;
|
|
603
|
+
docs: number;
|
|
604
|
+
generated: number;
|
|
605
|
+
} | null;
|
|
606
|
+
}>;
|
|
607
|
+
baseline: z.ZodObject<{
|
|
608
|
+
age: z.ZodNullable<z.ZodObject<{
|
|
609
|
+
commits: z.ZodNumber;
|
|
610
|
+
avgAgeDays: z.ZodNumber;
|
|
611
|
+
medianAgeDays: z.ZodNumber;
|
|
612
|
+
}, "strip", z.ZodTypeAny, {
|
|
613
|
+
commits: number;
|
|
614
|
+
avgAgeDays: number;
|
|
615
|
+
medianAgeDays: number;
|
|
616
|
+
}, {
|
|
617
|
+
commits: number;
|
|
618
|
+
avgAgeDays: number;
|
|
619
|
+
medianAgeDays: number;
|
|
620
|
+
}>>;
|
|
621
|
+
taskMix: z.ZodNullable<z.ZodObject<{
|
|
622
|
+
source: z.ZodNumber;
|
|
623
|
+
tests: z.ZodNumber;
|
|
624
|
+
migrations: z.ZodNumber;
|
|
625
|
+
config: z.ZodNumber;
|
|
626
|
+
docs: z.ZodNumber;
|
|
627
|
+
generated: z.ZodNumber;
|
|
628
|
+
}, "strip", z.ZodTypeAny, {
|
|
629
|
+
source: number;
|
|
630
|
+
tests: number;
|
|
631
|
+
migrations: number;
|
|
632
|
+
config: number;
|
|
633
|
+
docs: number;
|
|
634
|
+
generated: number;
|
|
635
|
+
}, {
|
|
636
|
+
source: number;
|
|
637
|
+
tests: number;
|
|
638
|
+
migrations: number;
|
|
639
|
+
config: number;
|
|
640
|
+
docs: number;
|
|
641
|
+
generated: number;
|
|
642
|
+
}>>;
|
|
643
|
+
}, "strip", z.ZodTypeAny, {
|
|
644
|
+
age: {
|
|
645
|
+
commits: number;
|
|
646
|
+
avgAgeDays: number;
|
|
647
|
+
medianAgeDays: number;
|
|
648
|
+
} | null;
|
|
649
|
+
taskMix: {
|
|
650
|
+
source: number;
|
|
651
|
+
tests: number;
|
|
652
|
+
migrations: number;
|
|
653
|
+
config: number;
|
|
654
|
+
docs: number;
|
|
655
|
+
generated: number;
|
|
656
|
+
} | null;
|
|
657
|
+
}, {
|
|
658
|
+
age: {
|
|
659
|
+
commits: number;
|
|
660
|
+
avgAgeDays: number;
|
|
661
|
+
medianAgeDays: number;
|
|
662
|
+
} | null;
|
|
663
|
+
taskMix: {
|
|
664
|
+
source: number;
|
|
665
|
+
tests: number;
|
|
666
|
+
migrations: number;
|
|
667
|
+
config: number;
|
|
668
|
+
docs: number;
|
|
669
|
+
generated: number;
|
|
670
|
+
} | null;
|
|
671
|
+
}>;
|
|
672
|
+
}, "strip", z.ZodTypeAny, {
|
|
673
|
+
ai: {
|
|
674
|
+
age: {
|
|
675
|
+
commits: number;
|
|
676
|
+
avgAgeDays: number;
|
|
677
|
+
medianAgeDays: number;
|
|
678
|
+
} | null;
|
|
679
|
+
taskMix: {
|
|
680
|
+
source: number;
|
|
681
|
+
tests: number;
|
|
682
|
+
migrations: number;
|
|
683
|
+
config: number;
|
|
684
|
+
docs: number;
|
|
685
|
+
generated: number;
|
|
686
|
+
} | null;
|
|
687
|
+
};
|
|
688
|
+
baseline: {
|
|
689
|
+
age: {
|
|
690
|
+
commits: number;
|
|
691
|
+
avgAgeDays: number;
|
|
692
|
+
medianAgeDays: number;
|
|
693
|
+
} | null;
|
|
694
|
+
taskMix: {
|
|
695
|
+
source: number;
|
|
696
|
+
tests: number;
|
|
697
|
+
migrations: number;
|
|
698
|
+
config: number;
|
|
699
|
+
docs: number;
|
|
700
|
+
generated: number;
|
|
701
|
+
} | null;
|
|
702
|
+
};
|
|
703
|
+
}, {
|
|
704
|
+
ai: {
|
|
705
|
+
age: {
|
|
706
|
+
commits: number;
|
|
707
|
+
avgAgeDays: number;
|
|
708
|
+
medianAgeDays: number;
|
|
709
|
+
} | null;
|
|
710
|
+
taskMix: {
|
|
711
|
+
source: number;
|
|
712
|
+
tests: number;
|
|
713
|
+
migrations: number;
|
|
714
|
+
config: number;
|
|
715
|
+
docs: number;
|
|
716
|
+
generated: number;
|
|
717
|
+
} | null;
|
|
718
|
+
};
|
|
719
|
+
baseline: {
|
|
720
|
+
age: {
|
|
721
|
+
commits: number;
|
|
722
|
+
avgAgeDays: number;
|
|
723
|
+
medianAgeDays: number;
|
|
724
|
+
} | null;
|
|
725
|
+
taskMix: {
|
|
726
|
+
source: number;
|
|
727
|
+
tests: number;
|
|
728
|
+
migrations: number;
|
|
729
|
+
config: number;
|
|
730
|
+
docs: number;
|
|
731
|
+
generated: number;
|
|
732
|
+
} | null;
|
|
733
|
+
};
|
|
734
|
+
}>;
|
|
735
|
+
baseline: z.ZodNullable<z.ZodObject<{
|
|
736
|
+
assumed: z.ZodBoolean;
|
|
265
737
|
mergeRatio: z.ZodObject<{
|
|
266
738
|
commitsTotal: z.ZodNumber;
|
|
267
739
|
commitsMerged: z.ZodNumber;
|
|
268
740
|
mergeRatio: z.ZodNumber;
|
|
269
741
|
}, "strip", z.ZodTypeAny, {
|
|
270
|
-
mergeRatio: number;
|
|
271
742
|
commitsTotal: number;
|
|
743
|
+
mergeRatio: number;
|
|
272
744
|
commitsMerged: number;
|
|
273
745
|
}, {
|
|
274
|
-
mergeRatio: number;
|
|
275
746
|
commitsTotal: number;
|
|
747
|
+
mergeRatio: number;
|
|
276
748
|
commitsMerged: number;
|
|
277
749
|
}>;
|
|
278
750
|
persistence: z.ZodObject<{
|
|
@@ -323,8 +795,8 @@ declare const Metrics: z.ZodObject<{
|
|
|
323
795
|
}>;
|
|
324
796
|
}, "strip", z.ZodTypeAny, {
|
|
325
797
|
mergeRatio: {
|
|
326
|
-
mergeRatio: number;
|
|
327
798
|
commitsTotal: number;
|
|
799
|
+
mergeRatio: number;
|
|
328
800
|
commitsMerged: number;
|
|
329
801
|
};
|
|
330
802
|
persistence: {
|
|
@@ -339,10 +811,11 @@ declare const Metrics: z.ZodObject<{
|
|
|
339
811
|
d90_plus: number;
|
|
340
812
|
};
|
|
341
813
|
};
|
|
814
|
+
assumed: boolean;
|
|
342
815
|
}, {
|
|
343
816
|
mergeRatio: {
|
|
344
|
-
mergeRatio: number;
|
|
345
817
|
commitsTotal: number;
|
|
818
|
+
mergeRatio: number;
|
|
346
819
|
commitsMerged: number;
|
|
347
820
|
};
|
|
348
821
|
persistence: {
|
|
@@ -357,8 +830,9 @@ declare const Metrics: z.ZodObject<{
|
|
|
357
830
|
d90_plus: number;
|
|
358
831
|
};
|
|
359
832
|
};
|
|
360
|
-
|
|
361
|
-
|
|
833
|
+
assumed: boolean;
|
|
834
|
+
}>>;
|
|
835
|
+
delta: z.ZodNullable<z.ZodObject<{
|
|
362
836
|
mergeRatio: z.ZodNumber;
|
|
363
837
|
avgPersistenceDays: z.ZodNumber;
|
|
364
838
|
medianPersistenceDays: z.ZodNumber;
|
|
@@ -370,7 +844,7 @@ declare const Metrics: z.ZodObject<{
|
|
|
370
844
|
mergeRatio: number;
|
|
371
845
|
avgPersistenceDays: number;
|
|
372
846
|
medianPersistenceDays: number;
|
|
373
|
-
}
|
|
847
|
+
}>>;
|
|
374
848
|
caveats: z.ZodArray<z.ZodString, "many">;
|
|
375
849
|
}, "strip", z.ZodTypeAny, {
|
|
376
850
|
generatedAt: string;
|
|
@@ -380,6 +854,28 @@ declare const Metrics: z.ZodObject<{
|
|
|
380
854
|
};
|
|
381
855
|
repoPath: string;
|
|
382
856
|
defaultBranch: string;
|
|
857
|
+
attribution: {
|
|
858
|
+
ai: number;
|
|
859
|
+
human: number;
|
|
860
|
+
unknown: number;
|
|
861
|
+
commitsTotal: number;
|
|
862
|
+
coverage: number;
|
|
863
|
+
defaultAttribution: "ai" | "human" | "unknown";
|
|
864
|
+
coverageThreshold: number;
|
|
865
|
+
belowThreshold: boolean;
|
|
866
|
+
modes: {
|
|
867
|
+
unknown: number;
|
|
868
|
+
none: number;
|
|
869
|
+
autocomplete: number;
|
|
870
|
+
assisted: number;
|
|
871
|
+
agent: number;
|
|
872
|
+
};
|
|
873
|
+
modeEvidence: {
|
|
874
|
+
none: number;
|
|
875
|
+
declared: number;
|
|
876
|
+
inferred: number;
|
|
877
|
+
};
|
|
878
|
+
};
|
|
383
879
|
mergeRatio: {
|
|
384
880
|
aiCommitsTotal: number;
|
|
385
881
|
aiCommitsMerged: number;
|
|
@@ -397,10 +893,42 @@ declare const Metrics: z.ZodObject<{
|
|
|
397
893
|
d90_plus: number;
|
|
398
894
|
};
|
|
399
895
|
};
|
|
896
|
+
cohorts: {
|
|
897
|
+
ai: {
|
|
898
|
+
age: {
|
|
899
|
+
commits: number;
|
|
900
|
+
avgAgeDays: number;
|
|
901
|
+
medianAgeDays: number;
|
|
902
|
+
} | null;
|
|
903
|
+
taskMix: {
|
|
904
|
+
source: number;
|
|
905
|
+
tests: number;
|
|
906
|
+
migrations: number;
|
|
907
|
+
config: number;
|
|
908
|
+
docs: number;
|
|
909
|
+
generated: number;
|
|
910
|
+
} | null;
|
|
911
|
+
};
|
|
912
|
+
baseline: {
|
|
913
|
+
age: {
|
|
914
|
+
commits: number;
|
|
915
|
+
avgAgeDays: number;
|
|
916
|
+
medianAgeDays: number;
|
|
917
|
+
} | null;
|
|
918
|
+
taskMix: {
|
|
919
|
+
source: number;
|
|
920
|
+
tests: number;
|
|
921
|
+
migrations: number;
|
|
922
|
+
config: number;
|
|
923
|
+
docs: number;
|
|
924
|
+
generated: number;
|
|
925
|
+
} | null;
|
|
926
|
+
};
|
|
927
|
+
};
|
|
400
928
|
baseline: {
|
|
401
929
|
mergeRatio: {
|
|
402
|
-
mergeRatio: number;
|
|
403
930
|
commitsTotal: number;
|
|
931
|
+
mergeRatio: number;
|
|
404
932
|
commitsMerged: number;
|
|
405
933
|
};
|
|
406
934
|
persistence: {
|
|
@@ -415,12 +943,13 @@ declare const Metrics: z.ZodObject<{
|
|
|
415
943
|
d90_plus: number;
|
|
416
944
|
};
|
|
417
945
|
};
|
|
418
|
-
|
|
946
|
+
assumed: boolean;
|
|
947
|
+
} | null;
|
|
419
948
|
delta: {
|
|
420
949
|
mergeRatio: number;
|
|
421
950
|
avgPersistenceDays: number;
|
|
422
951
|
medianPersistenceDays: number;
|
|
423
|
-
};
|
|
952
|
+
} | null;
|
|
424
953
|
caveats: string[];
|
|
425
954
|
}, {
|
|
426
955
|
generatedAt: string;
|
|
@@ -430,6 +959,28 @@ declare const Metrics: z.ZodObject<{
|
|
|
430
959
|
};
|
|
431
960
|
repoPath: string;
|
|
432
961
|
defaultBranch: string;
|
|
962
|
+
attribution: {
|
|
963
|
+
ai: number;
|
|
964
|
+
human: number;
|
|
965
|
+
unknown: number;
|
|
966
|
+
commitsTotal: number;
|
|
967
|
+
coverage: number;
|
|
968
|
+
defaultAttribution: "ai" | "human" | "unknown";
|
|
969
|
+
coverageThreshold: number;
|
|
970
|
+
belowThreshold: boolean;
|
|
971
|
+
modes: {
|
|
972
|
+
unknown: number;
|
|
973
|
+
none: number;
|
|
974
|
+
autocomplete: number;
|
|
975
|
+
assisted: number;
|
|
976
|
+
agent: number;
|
|
977
|
+
};
|
|
978
|
+
modeEvidence: {
|
|
979
|
+
none: number;
|
|
980
|
+
declared: number;
|
|
981
|
+
inferred: number;
|
|
982
|
+
};
|
|
983
|
+
};
|
|
433
984
|
mergeRatio: {
|
|
434
985
|
aiCommitsTotal: number;
|
|
435
986
|
aiCommitsMerged: number;
|
|
@@ -447,10 +998,42 @@ declare const Metrics: z.ZodObject<{
|
|
|
447
998
|
d90_plus: number;
|
|
448
999
|
};
|
|
449
1000
|
};
|
|
1001
|
+
cohorts: {
|
|
1002
|
+
ai: {
|
|
1003
|
+
age: {
|
|
1004
|
+
commits: number;
|
|
1005
|
+
avgAgeDays: number;
|
|
1006
|
+
medianAgeDays: number;
|
|
1007
|
+
} | null;
|
|
1008
|
+
taskMix: {
|
|
1009
|
+
source: number;
|
|
1010
|
+
tests: number;
|
|
1011
|
+
migrations: number;
|
|
1012
|
+
config: number;
|
|
1013
|
+
docs: number;
|
|
1014
|
+
generated: number;
|
|
1015
|
+
} | null;
|
|
1016
|
+
};
|
|
1017
|
+
baseline: {
|
|
1018
|
+
age: {
|
|
1019
|
+
commits: number;
|
|
1020
|
+
avgAgeDays: number;
|
|
1021
|
+
medianAgeDays: number;
|
|
1022
|
+
} | null;
|
|
1023
|
+
taskMix: {
|
|
1024
|
+
source: number;
|
|
1025
|
+
tests: number;
|
|
1026
|
+
migrations: number;
|
|
1027
|
+
config: number;
|
|
1028
|
+
docs: number;
|
|
1029
|
+
generated: number;
|
|
1030
|
+
} | null;
|
|
1031
|
+
};
|
|
1032
|
+
};
|
|
450
1033
|
baseline: {
|
|
451
1034
|
mergeRatio: {
|
|
452
|
-
mergeRatio: number;
|
|
453
1035
|
commitsTotal: number;
|
|
1036
|
+
mergeRatio: number;
|
|
454
1037
|
commitsMerged: number;
|
|
455
1038
|
};
|
|
456
1039
|
persistence: {
|
|
@@ -465,22 +1048,31 @@ declare const Metrics: z.ZodObject<{
|
|
|
465
1048
|
d90_plus: number;
|
|
466
1049
|
};
|
|
467
1050
|
};
|
|
468
|
-
|
|
1051
|
+
assumed: boolean;
|
|
1052
|
+
} | null;
|
|
469
1053
|
delta: {
|
|
470
1054
|
mergeRatio: number;
|
|
471
1055
|
avgPersistenceDays: number;
|
|
472
1056
|
medianPersistenceDays: number;
|
|
473
|
-
};
|
|
1057
|
+
} | null;
|
|
474
1058
|
caveats: string[];
|
|
475
1059
|
}>;
|
|
476
1060
|
type Metrics = z.infer<typeof Metrics>;
|
|
477
1061
|
|
|
478
|
-
declare function
|
|
479
|
-
declare function
|
|
1062
|
+
declare function calculateAgeStats(commits: Commit[], now: Date): AgeStats | null;
|
|
1063
|
+
declare function categorizeFile(path: string): FileCategory;
|
|
1064
|
+
declare function calculateCategoryCounts(commits: Commit[]): CategoryCounts | null;
|
|
1065
|
+
|
|
1066
|
+
declare function calculateMergeRatio(commitStream: CommitStream, isTarget?: (commit: Commit) => boolean): MergeRatio;
|
|
1067
|
+
declare function calculateBaselineMergeRatio(commitStream: CommitStream, isTarget?: (commit: Commit) => boolean): CohortMergeRatio;
|
|
480
1068
|
|
|
481
1069
|
declare function calculatePersistence(commitStream: CommitStream, isTarget?: (commit: Commit) => boolean): Persistence;
|
|
482
|
-
declare function calculateBaselinePersistence(commitStream: CommitStream): Persistence;
|
|
1070
|
+
declare function calculateBaselinePersistence(commitStream: CommitStream, isTarget?: (commit: Commit) => boolean): Persistence;
|
|
483
1071
|
|
|
484
|
-
|
|
1072
|
+
interface MetricsOptions {
|
|
1073
|
+
defaultAttribution?: 'ai' | 'human' | 'unknown';
|
|
1074
|
+
coverageThreshold?: number;
|
|
1075
|
+
}
|
|
1076
|
+
declare function calculateMetrics(commitStream: CommitStream, options?: MetricsOptions): Metrics;
|
|
485
1077
|
|
|
486
|
-
export { Baseline, CohortMergeRatio, Delta, MergeRatio, Metrics, Persistence, calculateBaselineMergeRatio, calculateBaselinePersistence, calculateMergeRatio, calculateMetrics, calculatePersistence };
|
|
1078
|
+
export { AgeStats, Attribution, Baseline, CategoryCounts, CohortContext, CohortMergeRatio, Delta, FileCategory, MergeRatio, Metrics, type MetricsOptions, Persistence, calculateAgeStats, calculateBaselineMergeRatio, calculateBaselinePersistence, calculateCategoryCounts, calculateMergeRatio, calculateMetrics, calculatePersistence, categorizeFile };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,63 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { formatISODate } from "@aida-dev/core";
|
|
3
3
|
|
|
4
|
+
// src/cohort.ts
|
|
5
|
+
import { daysBetween } from "@aida-dev/core";
|
|
6
|
+
function calculateAgeStats(commits, now) {
|
|
7
|
+
if (commits.length === 0) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
const ages = commits.map((commit) => daysBetween(new Date(commit.authorDate), now)).sort((a, b) => a - b);
|
|
11
|
+
const avg = ages.reduce((sum, days) => sum + days, 0) / ages.length;
|
|
12
|
+
const median = ages.length % 2 === 0 ? (ages[ages.length / 2 - 1] + ages[ages.length / 2]) / 2 : ages[Math.floor(ages.length / 2)];
|
|
13
|
+
return {
|
|
14
|
+
commits: commits.length,
|
|
15
|
+
avgAgeDays: Math.round(avg * 100) / 100,
|
|
16
|
+
medianAgeDays: Math.round(median * 100) / 100
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function categorizeFile(path) {
|
|
20
|
+
const lower = path.toLowerCase();
|
|
21
|
+
const base = lower.split("/").pop() ?? lower;
|
|
22
|
+
if (/^(pnpm-lock\.yaml|package-lock\.json|yarn\.lock|bun\.lockb?|composer\.lock|cargo\.lock|gemfile\.lock|poetry\.lock|changelog(\.[a-z]+)?)$/.test(
|
|
23
|
+
base
|
|
24
|
+
) || /\.(snap|min\.js|min\.css)$/.test(base) || /(^|\/)(dist|build|out|coverage|\.next|node_modules)\//.test(lower)) {
|
|
25
|
+
return "generated";
|
|
26
|
+
}
|
|
27
|
+
if (/(^|\/)(__tests__|__mocks__|tests?|spec|e2e|cypress)\//.test(lower) || /\.(test|spec)\.[a-z]+$/.test(base)) {
|
|
28
|
+
return "tests";
|
|
29
|
+
}
|
|
30
|
+
if (/(^|\/)migrations?\//.test(lower)) {
|
|
31
|
+
return "migrations";
|
|
32
|
+
}
|
|
33
|
+
if (/\.(md|mdx|rst|adoc|txt)$/.test(base) || /(^|\/)docs?\//.test(lower)) {
|
|
34
|
+
return "docs";
|
|
35
|
+
}
|
|
36
|
+
if (base.startsWith(".") || /\.(json|ya?ml|toml|ini|cfg|conf|env|properties)$/.test(base) || /\.config\.[a-z]+$/.test(base) || /(^|\/)(\.github|\.circleci|\.vscode|config)\//.test(lower) || /^(dockerfile|makefile|tsconfig.*|eslint.*|prettier.*)/.test(base)) {
|
|
37
|
+
return "config";
|
|
38
|
+
}
|
|
39
|
+
return "source";
|
|
40
|
+
}
|
|
41
|
+
function calculateCategoryCounts(commits) {
|
|
42
|
+
if (commits.length === 0) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const counts = {
|
|
46
|
+
source: 0,
|
|
47
|
+
tests: 0,
|
|
48
|
+
migrations: 0,
|
|
49
|
+
config: 0,
|
|
50
|
+
docs: 0,
|
|
51
|
+
generated: 0
|
|
52
|
+
};
|
|
53
|
+
for (const commit of commits) {
|
|
54
|
+
for (const file of commit.stats.files) {
|
|
55
|
+
counts[categorizeFile(file.path)]++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return counts;
|
|
59
|
+
}
|
|
60
|
+
|
|
4
61
|
// src/merge-ratio.ts
|
|
5
62
|
function computeMergeRatio(commits) {
|
|
6
63
|
const merged = commits.filter((commit) => commit.inDefaultBranchAncestry);
|
|
@@ -10,8 +67,8 @@ function computeMergeRatio(commits) {
|
|
|
10
67
|
mergeRatio: commits.length > 0 ? merged.length / commits.length : 0
|
|
11
68
|
};
|
|
12
69
|
}
|
|
13
|
-
function calculateMergeRatio(commitStream) {
|
|
14
|
-
const aiCommits = commitStream.commits.filter(
|
|
70
|
+
function calculateMergeRatio(commitStream, isTarget = (commit) => commit.tags.attribution === "ai") {
|
|
71
|
+
const aiCommits = commitStream.commits.filter(isTarget);
|
|
15
72
|
const result = computeMergeRatio(aiCommits);
|
|
16
73
|
return {
|
|
17
74
|
aiCommitsTotal: result.commitsTotal,
|
|
@@ -19,14 +76,14 @@ function calculateMergeRatio(commitStream) {
|
|
|
19
76
|
mergeRatio: result.mergeRatio
|
|
20
77
|
};
|
|
21
78
|
}
|
|
22
|
-
function calculateBaselineMergeRatio(commitStream) {
|
|
23
|
-
const
|
|
24
|
-
return computeMergeRatio(
|
|
79
|
+
function calculateBaselineMergeRatio(commitStream, isTarget = (commit) => commit.tags.attribution === "human") {
|
|
80
|
+
const baselineCommits = commitStream.commits.filter(isTarget);
|
|
81
|
+
return computeMergeRatio(baselineCommits);
|
|
25
82
|
}
|
|
26
83
|
|
|
27
84
|
// src/persistence.ts
|
|
28
|
-
import { daysBetween } from "@aida-dev/core";
|
|
29
|
-
function calculatePersistence(commitStream, isTarget = (commit) => commit.tags.ai) {
|
|
85
|
+
import { daysBetween as daysBetween2 } from "@aida-dev/core";
|
|
86
|
+
function calculatePersistence(commitStream, isTarget = (commit) => commit.tags.attribution === "ai") {
|
|
30
87
|
const targetCommits = commitStream.commits.filter(isTarget);
|
|
31
88
|
if (targetCommits.length === 0) {
|
|
32
89
|
return {
|
|
@@ -74,7 +131,7 @@ function calculatePersistence(commitStream, isTarget = (commit) => commit.tags.a
|
|
|
74
131
|
}
|
|
75
132
|
const persistenceDays = [];
|
|
76
133
|
for (const lifecycle of fileLifecycles.values()) {
|
|
77
|
-
lifecycle.persistenceDays =
|
|
134
|
+
lifecycle.persistenceDays = daysBetween2(lifecycle.firstTargetCommitDate, lifecycle.lastSeenDate);
|
|
78
135
|
persistenceDays.push(lifecycle.persistenceDays);
|
|
79
136
|
}
|
|
80
137
|
const avgDays = persistenceDays.length > 0 ? persistenceDays.reduce((sum, days) => sum + days, 0) / persistenceDays.length : 0;
|
|
@@ -95,12 +152,37 @@ function calculatePersistence(commitStream, isTarget = (commit) => commit.tags.a
|
|
|
95
152
|
buckets
|
|
96
153
|
};
|
|
97
154
|
}
|
|
98
|
-
function calculateBaselinePersistence(commitStream) {
|
|
99
|
-
return calculatePersistence(commitStream,
|
|
155
|
+
function calculateBaselinePersistence(commitStream, isTarget = (commit) => commit.tags.attribution === "human") {
|
|
156
|
+
return calculatePersistence(commitStream, isTarget);
|
|
100
157
|
}
|
|
101
158
|
|
|
102
159
|
// src/schema/metrics.ts
|
|
103
160
|
import { z } from "zod";
|
|
161
|
+
var Attribution = z.object({
|
|
162
|
+
commitsTotal: z.number().int().nonnegative(),
|
|
163
|
+
ai: z.number().int().nonnegative(),
|
|
164
|
+
human: z.number().int().nonnegative(),
|
|
165
|
+
unknown: z.number().int().nonnegative(),
|
|
166
|
+
coverage: z.number().min(0).max(1),
|
|
167
|
+
// (ai + human) / total
|
|
168
|
+
defaultAttribution: z.enum(["ai", "human", "unknown"]),
|
|
169
|
+
// prior applied to unknown commits
|
|
170
|
+
coverageThreshold: z.number().min(0).max(1),
|
|
171
|
+
belowThreshold: z.boolean(),
|
|
172
|
+
// Autonomy axis (#25): commit counts per mode and per mode-evidence level
|
|
173
|
+
modes: z.object({
|
|
174
|
+
none: z.number().int().nonnegative(),
|
|
175
|
+
autocomplete: z.number().int().nonnegative(),
|
|
176
|
+
assisted: z.number().int().nonnegative(),
|
|
177
|
+
agent: z.number().int().nonnegative(),
|
|
178
|
+
unknown: z.number().int().nonnegative()
|
|
179
|
+
}),
|
|
180
|
+
modeEvidence: z.object({
|
|
181
|
+
declared: z.number().int().nonnegative(),
|
|
182
|
+
inferred: z.number().int().nonnegative(),
|
|
183
|
+
none: z.number().int().nonnegative()
|
|
184
|
+
})
|
|
185
|
+
});
|
|
104
186
|
var MergeRatio = z.object({
|
|
105
187
|
aiCommitsTotal: z.number().int().nonnegative(),
|
|
106
188
|
aiCommitsMerged: z.number().int().nonnegative(),
|
|
@@ -118,12 +200,40 @@ var Persistence = z.object({
|
|
|
118
200
|
d90_plus: z.number().int().nonnegative()
|
|
119
201
|
})
|
|
120
202
|
});
|
|
203
|
+
var AgeStats = z.object({
|
|
204
|
+
commits: z.number().int().nonnegative(),
|
|
205
|
+
avgAgeDays: z.number().nonnegative(),
|
|
206
|
+
medianAgeDays: z.number().nonnegative()
|
|
207
|
+
});
|
|
208
|
+
var FileCategory = z.enum([
|
|
209
|
+
"source",
|
|
210
|
+
"tests",
|
|
211
|
+
"migrations",
|
|
212
|
+
"config",
|
|
213
|
+
"docs",
|
|
214
|
+
"generated"
|
|
215
|
+
]);
|
|
216
|
+
var CategoryCounts = z.object({
|
|
217
|
+
source: z.number().int().nonnegative(),
|
|
218
|
+
tests: z.number().int().nonnegative(),
|
|
219
|
+
migrations: z.number().int().nonnegative(),
|
|
220
|
+
config: z.number().int().nonnegative(),
|
|
221
|
+
docs: z.number().int().nonnegative(),
|
|
222
|
+
generated: z.number().int().nonnegative()
|
|
223
|
+
});
|
|
224
|
+
var CohortContext = z.object({
|
|
225
|
+
age: AgeStats.nullable(),
|
|
226
|
+
taskMix: CategoryCounts.nullable()
|
|
227
|
+
});
|
|
121
228
|
var CohortMergeRatio = z.object({
|
|
122
229
|
commitsTotal: z.number().int().nonnegative(),
|
|
123
230
|
commitsMerged: z.number().int().nonnegative(),
|
|
124
231
|
mergeRatio: z.number().min(0).max(1)
|
|
125
232
|
});
|
|
126
233
|
var Baseline = z.object({
|
|
234
|
+
// True when the cohort includes 'unknown' commits via defaultAttribution:
|
|
235
|
+
// the baseline is an assumption, not observed attribution.
|
|
236
|
+
assumed: z.boolean(),
|
|
127
237
|
mergeRatio: CohortMergeRatio,
|
|
128
238
|
persistence: Persistence
|
|
129
239
|
});
|
|
@@ -140,10 +250,19 @@ var Metrics = z.object({
|
|
|
140
250
|
}),
|
|
141
251
|
repoPath: z.string(),
|
|
142
252
|
defaultBranch: z.string(),
|
|
253
|
+
attribution: Attribution,
|
|
143
254
|
mergeRatio: MergeRatio,
|
|
144
255
|
persistence: Persistence,
|
|
145
|
-
|
|
146
|
-
|
|
256
|
+
// Fairness context (#29, #36): age and task mix per cohort, so consumers
|
|
257
|
+
// can judge whether the AI-vs-baseline comparison is apples-to-apples.
|
|
258
|
+
cohorts: z.object({
|
|
259
|
+
ai: CohortContext,
|
|
260
|
+
baseline: CohortContext
|
|
261
|
+
}),
|
|
262
|
+
// Null when no commit is attributed 'human' and no defaultAttribution prior
|
|
263
|
+
// assigns the unknowns: AIDA does not invent a comparison cohort.
|
|
264
|
+
baseline: Baseline.nullable(),
|
|
265
|
+
delta: Delta.nullable(),
|
|
147
266
|
caveats: z.array(z.string())
|
|
148
267
|
});
|
|
149
268
|
|
|
@@ -152,22 +271,81 @@ function round(value, decimals) {
|
|
|
152
271
|
const factor = 10 ** decimals;
|
|
153
272
|
return Math.round(value * factor) / factor;
|
|
154
273
|
}
|
|
155
|
-
function calculateMetrics(commitStream) {
|
|
156
|
-
const
|
|
157
|
-
const
|
|
158
|
-
const
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
274
|
+
function calculateMetrics(commitStream, options = {}) {
|
|
275
|
+
const { defaultAttribution = "unknown", coverageThreshold = 0.7 } = options;
|
|
276
|
+
const counts = { ai: 0, human: 0, unknown: 0 };
|
|
277
|
+
const modes = { none: 0, autocomplete: 0, assisted: 0, agent: 0, unknown: 0 };
|
|
278
|
+
const modeEvidence = { declared: 0, inferred: 0, none: 0 };
|
|
279
|
+
for (const commit of commitStream.commits) {
|
|
280
|
+
counts[commit.tags.attribution]++;
|
|
281
|
+
modes[commit.tags.mode]++;
|
|
282
|
+
modeEvidence[commit.tags.modeEvidence]++;
|
|
283
|
+
}
|
|
284
|
+
const total = commitStream.commits.length;
|
|
285
|
+
const coverage = total > 0 ? (counts.ai + counts.human) / total : 0;
|
|
286
|
+
const attribution = {
|
|
287
|
+
commitsTotal: total,
|
|
288
|
+
ai: counts.ai,
|
|
289
|
+
human: counts.human,
|
|
290
|
+
unknown: counts.unknown,
|
|
291
|
+
coverage: round(coverage, 4),
|
|
292
|
+
defaultAttribution,
|
|
293
|
+
coverageThreshold,
|
|
294
|
+
belowThreshold: coverage < coverageThreshold,
|
|
295
|
+
modes,
|
|
296
|
+
modeEvidence
|
|
297
|
+
};
|
|
298
|
+
const isExcluded = (commit) => commit.tags.sources.includes("manifest:excluded");
|
|
299
|
+
const isAI = (commit) => commit.tags.attribution === "ai" || defaultAttribution === "ai" && commit.tags.attribution === "unknown" && !isExcluded(commit);
|
|
300
|
+
const isBaseline = (commit) => commit.tags.attribution === "human" || defaultAttribution === "human" && commit.tags.attribution === "unknown" && !isExcluded(commit);
|
|
301
|
+
const mergeRatio = calculateMergeRatio(commitStream, isAI);
|
|
302
|
+
const persistence = calculatePersistence(commitStream, isAI);
|
|
303
|
+
const now = /* @__PURE__ */ new Date();
|
|
304
|
+
const aiCommits = commitStream.commits.filter(isAI);
|
|
305
|
+
const baselineCommits = commitStream.commits.filter(isBaseline);
|
|
306
|
+
const cohorts = {
|
|
307
|
+
ai: {
|
|
308
|
+
age: calculateAgeStats(aiCommits, now),
|
|
309
|
+
taskMix: calculateCategoryCounts(aiCommits)
|
|
310
|
+
},
|
|
311
|
+
baseline: {
|
|
312
|
+
age: calculateAgeStats(baselineCommits, now),
|
|
313
|
+
taskMix: calculateCategoryCounts(baselineCommits)
|
|
314
|
+
}
|
|
164
315
|
};
|
|
316
|
+
const baselineSize = baselineCommits.length;
|
|
317
|
+
const baselineAssumed = defaultAttribution === "human" && counts.unknown > 0;
|
|
318
|
+
const baseline = baselineSize > 0 ? {
|
|
319
|
+
assumed: baselineAssumed,
|
|
320
|
+
mergeRatio: calculateBaselineMergeRatio(commitStream, isBaseline),
|
|
321
|
+
persistence: calculateBaselinePersistence(commitStream, isBaseline)
|
|
322
|
+
} : null;
|
|
323
|
+
const delta = baseline ? {
|
|
324
|
+
mergeRatio: round(mergeRatio.mergeRatio - baseline.mergeRatio.mergeRatio, 4),
|
|
325
|
+
avgPersistenceDays: round(persistence.avgDays - baseline.persistence.avgDays, 2),
|
|
326
|
+
medianPersistenceDays: round(
|
|
327
|
+
persistence.medianDays - baseline.persistence.medianDays,
|
|
328
|
+
2
|
|
329
|
+
)
|
|
330
|
+
} : null;
|
|
165
331
|
const caveats = [
|
|
332
|
+
`Attribution coverage is ${(coverage * 100).toFixed(1)}%: metrics only describe commits whose provenance is known.`,
|
|
166
333
|
"Persistence is file-level, not line-level.",
|
|
334
|
+
"Persistence comparisons are only meaningful between cohorts of similar age and task mix \u2014 check the cohorts section before reading the delta.",
|
|
167
335
|
"Merge ratio: commits from all branches checked against default branch ancestry. Squash merges may undercount unmerged commits.",
|
|
168
|
-
"
|
|
169
|
-
"
|
|
336
|
+
"Time-windowed collection (--since) also windows the ancestry check: commits merged into the default branch before the window may appear unmerged.",
|
|
337
|
+
"AI tagging uses heuristic patterns; false positives/negatives possible."
|
|
170
338
|
];
|
|
339
|
+
if (baseline?.assumed) {
|
|
340
|
+
caveats.push(
|
|
341
|
+
`Baseline includes ${counts.unknown} unattributed commit(s) assumed human via defaultAttribution \u2014 undetected AI usage may leak into it.`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
if (!baseline) {
|
|
345
|
+
caveats.push(
|
|
346
|
+
'No baseline: no commits are attributed as human. Set defaultAttribution to "human" in .aida.json if unattributed commits in this repo are human-authored.'
|
|
347
|
+
);
|
|
348
|
+
}
|
|
171
349
|
return {
|
|
172
350
|
generatedAt: formatISODate(/* @__PURE__ */ new Date()),
|
|
173
351
|
window: {
|
|
@@ -176,27 +354,34 @@ function calculateMetrics(commitStream) {
|
|
|
176
354
|
},
|
|
177
355
|
repoPath: commitStream.repoPath,
|
|
178
356
|
defaultBranch: commitStream.defaultBranch,
|
|
357
|
+
attribution,
|
|
179
358
|
mergeRatio,
|
|
180
359
|
persistence,
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
persistence: baselinePersistence
|
|
184
|
-
},
|
|
360
|
+
cohorts,
|
|
361
|
+
baseline,
|
|
185
362
|
delta,
|
|
186
363
|
caveats
|
|
187
364
|
};
|
|
188
365
|
}
|
|
189
366
|
export {
|
|
367
|
+
AgeStats,
|
|
368
|
+
Attribution,
|
|
190
369
|
Baseline,
|
|
370
|
+
CategoryCounts,
|
|
371
|
+
CohortContext,
|
|
191
372
|
CohortMergeRatio,
|
|
192
373
|
Delta,
|
|
374
|
+
FileCategory,
|
|
193
375
|
MergeRatio,
|
|
194
376
|
Metrics,
|
|
195
377
|
Persistence,
|
|
378
|
+
calculateAgeStats,
|
|
196
379
|
calculateBaselineMergeRatio,
|
|
197
380
|
calculateBaselinePersistence,
|
|
381
|
+
calculateCategoryCounts,
|
|
198
382
|
calculateMergeRatio,
|
|
199
383
|
calculateMetrics,
|
|
200
|
-
calculatePersistence
|
|
384
|
+
calculatePersistence,
|
|
385
|
+
categorizeFile
|
|
201
386
|
};
|
|
202
387
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/merge-ratio.ts","../src/persistence.ts","../src/schema/metrics.ts"],"sourcesContent":["import { CommitStream, formatISODate } from '@aida-dev/core';\nimport { calculateBaselineMergeRatio, calculateMergeRatio } from './merge-ratio.js';\nimport { calculateBaselinePersistence, calculatePersistence } from './persistence.js';\nimport { Metrics } from './schema/metrics.js';\n\nexport * from './schema/metrics.js';\nexport * from './merge-ratio.js';\nexport * from './persistence.js';\n\nfunction round(value: number, decimals: number): number {\n const factor = 10 ** decimals;\n return Math.round(value * factor) / factor;\n}\n\nexport function calculateMetrics(commitStream: CommitStream): Metrics {\n const mergeRatio = calculateMergeRatio(commitStream);\n const persistence = calculatePersistence(commitStream);\n const baselineMergeRatio = calculateBaselineMergeRatio(commitStream);\n const baselinePersistence = calculateBaselinePersistence(commitStream);\n\n const delta = {\n mergeRatio: round(mergeRatio.mergeRatio - baselineMergeRatio.mergeRatio, 4),\n avgPersistenceDays: round(persistence.avgDays - baselinePersistence.avgDays, 2),\n medianPersistenceDays: round(persistence.medianDays - baselinePersistence.medianDays, 2),\n };\n\n const caveats = [\n 'Persistence is file-level, not line-level.',\n 'Merge ratio: commits from all branches checked against default branch ancestry. Squash merges may undercount unmerged commits.',\n 'AI tagging uses heuristic patterns; false positives/negatives possible.',\n 'Baseline covers all non-AI-tagged commits; undetected AI usage may leak into the baseline.',\n ];\n\n return {\n generatedAt: formatISODate(new Date()),\n window: {\n since: commitStream.since,\n until: commitStream.until,\n },\n repoPath: commitStream.repoPath,\n defaultBranch: commitStream.defaultBranch,\n mergeRatio,\n persistence,\n baseline: {\n mergeRatio: baselineMergeRatio,\n persistence: baselinePersistence,\n },\n delta,\n caveats,\n };\n}\n","import { Commit, CommitStream } from '@aida-dev/core';\nimport { CohortMergeRatio, MergeRatio } from './schema/metrics.js';\n\nfunction computeMergeRatio(commits: Commit[]): CohortMergeRatio {\n const merged = commits.filter((commit) => commit.inDefaultBranchAncestry);\n\n return {\n commitsTotal: commits.length,\n commitsMerged: merged.length,\n mergeRatio: commits.length > 0 ? merged.length / commits.length : 0,\n };\n}\n\nexport function calculateMergeRatio(commitStream: CommitStream): MergeRatio {\n const aiCommits = commitStream.commits.filter((commit) => commit.tags.ai);\n const result = computeMergeRatio(aiCommits);\n\n return {\n aiCommitsTotal: result.commitsTotal,\n aiCommitsMerged: result.commitsMerged,\n mergeRatio: result.mergeRatio,\n };\n}\n\nexport function calculateBaselineMergeRatio(commitStream: CommitStream): CohortMergeRatio {\n const nonAICommits = commitStream.commits.filter((commit) => !commit.tags.ai);\n return computeMergeRatio(nonAICommits);\n}\n","import { Commit, CommitStream, daysBetween } from '@aida-dev/core';\nimport { Persistence } from './schema/metrics.js';\n\ninterface FileLifecycle {\n path: string;\n firstTargetCommitDate: Date;\n lastSeenDate: Date;\n persistenceDays: number;\n}\n\nexport function calculatePersistence(\n commitStream: CommitStream,\n isTarget: (commit: Commit) => boolean = (commit) => commit.tags.ai\n): Persistence {\n const targetCommits = commitStream.commits.filter(isTarget);\n\n if (targetCommits.length === 0) {\n return {\n commitsConsidered: 0,\n avgDays: 0,\n medianDays: 0,\n buckets: {\n d0_1: 0,\n d2_7: 0,\n d8_30: 0,\n d31_90: 0,\n d90_plus: 0,\n },\n };\n }\n\n // Group files by path and track their lifecycle\n const fileLifecycles = new Map<string, FileLifecycle>();\n\n // Sort commits by date (oldest first)\n const sortedCommits = [...commitStream.commits].sort(\n (a, b) => new Date(a.authorDate).getTime() - new Date(b.authorDate).getTime()\n );\n\n // Track first target commit per file\n for (const commit of sortedCommits) {\n if (isTarget(commit)) {\n const commitDate = new Date(commit.authorDate);\n\n for (const file of commit.stats.files) {\n if (!fileLifecycles.has(file.path)) {\n fileLifecycles.set(file.path, {\n path: file.path,\n firstTargetCommitDate: commitDate,\n lastSeenDate: commitDate,\n persistenceDays: 0,\n });\n }\n }\n }\n }\n\n // Track last seen date for each file\n for (const commit of sortedCommits) {\n const commitDate = new Date(commit.authorDate);\n\n for (const file of commit.stats.files) {\n const lifecycle = fileLifecycles.get(file.path);\n if (lifecycle) {\n // Update last seen date if file is not deleted\n if (file.status !== 'deleted') {\n lifecycle.lastSeenDate = commitDate;\n }\n }\n }\n }\n\n // Calculate persistence days for each file\n const persistenceDays: number[] = [];\n\n for (const lifecycle of fileLifecycles.values()) {\n lifecycle.persistenceDays = daysBetween(lifecycle.firstTargetCommitDate, lifecycle.lastSeenDate);\n persistenceDays.push(lifecycle.persistenceDays);\n }\n\n // Calculate statistics\n const avgDays =\n persistenceDays.length > 0\n ? persistenceDays.reduce((sum, days) => sum + days, 0) / persistenceDays.length\n : 0;\n\n const sortedDays = [...persistenceDays].sort((a, b) => a - b);\n const medianDays =\n sortedDays.length > 0\n ? sortedDays.length % 2 === 0\n ? (sortedDays[sortedDays.length / 2 - 1] + sortedDays[sortedDays.length / 2]) / 2\n : sortedDays[Math.floor(sortedDays.length / 2)]\n : 0;\n\n // Calculate buckets\n const buckets = {\n d0_1: persistenceDays.filter((days) => days <= 1).length,\n d2_7: persistenceDays.filter((days) => days >= 2 && days <= 7).length,\n d8_30: persistenceDays.filter((days) => days >= 8 && days <= 30).length,\n d31_90: persistenceDays.filter((days) => days >= 31 && days <= 90).length,\n d90_plus: persistenceDays.filter((days) => days > 90).length,\n };\n\n return {\n commitsConsidered: targetCommits.length,\n avgDays: Math.round(avgDays * 100) / 100, // Round to 2 decimal places\n medianDays: Math.round(medianDays * 100) / 100,\n buckets,\n };\n}\n\nexport function calculateBaselinePersistence(commitStream: CommitStream): Persistence {\n return calculatePersistence(commitStream, (commit) => !commit.tags.ai);\n}\n","import { z } from 'zod';\n\nexport const MergeRatio = z.object({\n aiCommitsTotal: z.number().int().nonnegative(),\n aiCommitsMerged: z.number().int().nonnegative(),\n mergeRatio: z.number().min(0).max(1),\n});\n\nexport const Persistence = z.object({\n commitsConsidered: z.number().int().nonnegative(),\n avgDays: z.number().nonnegative(),\n medianDays: z.number().nonnegative(),\n buckets: z.object({\n d0_1: z.number().int().nonnegative(),\n d2_7: z.number().int().nonnegative(),\n d8_30: z.number().int().nonnegative(),\n d31_90: z.number().int().nonnegative(),\n d90_plus: z.number().int().nonnegative(),\n }),\n});\n\nexport const CohortMergeRatio = z.object({\n commitsTotal: z.number().int().nonnegative(),\n commitsMerged: z.number().int().nonnegative(),\n mergeRatio: z.number().min(0).max(1),\n});\n\nexport const Baseline = z.object({\n mergeRatio: CohortMergeRatio,\n persistence: Persistence,\n});\n\nexport const Delta = z.object({\n mergeRatio: z.number(),\n avgPersistenceDays: z.number(),\n medianPersistenceDays: z.number(),\n});\n\nexport const Metrics = z.object({\n generatedAt: z.string().datetime(),\n window: z.object({\n since: z.string().optional(),\n until: z.string().optional(),\n }),\n repoPath: z.string(),\n defaultBranch: z.string(),\n mergeRatio: MergeRatio,\n persistence: Persistence,\n baseline: Baseline,\n delta: Delta,\n caveats: z.array(z.string()),\n});\n\nexport type MergeRatio = z.infer<typeof MergeRatio>;\nexport type Persistence = z.infer<typeof Persistence>;\nexport type CohortMergeRatio = z.infer<typeof CohortMergeRatio>;\nexport type Baseline = z.infer<typeof Baseline>;\nexport type Delta = z.infer<typeof Delta>;\nexport type Metrics = z.infer<typeof Metrics>;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/cohort.ts","../src/merge-ratio.ts","../src/persistence.ts","../src/schema/metrics.ts"],"sourcesContent":["import { Commit, CommitStream, formatISODate } from '@aida-dev/core';\nimport { calculateAgeStats, calculateCategoryCounts } from './cohort.js';\nimport { calculateBaselineMergeRatio, calculateMergeRatio } from './merge-ratio.js';\nimport { calculateBaselinePersistence, calculatePersistence } from './persistence.js';\nimport { Attribution, Metrics } from './schema/metrics.js';\n\nexport * from './schema/metrics.js';\nexport * from './cohort.js';\nexport * from './merge-ratio.js';\nexport * from './persistence.js';\n\nexport interface MetricsOptions {\n // Prior applied to 'unknown' commits: which cohort (if any) they join.\n defaultAttribution?: 'ai' | 'human' | 'unknown';\n coverageThreshold?: number;\n}\n\nfunction round(value: number, decimals: number): number {\n const factor = 10 ** decimals;\n return Math.round(value * factor) / factor;\n}\n\nexport function calculateMetrics(\n commitStream: CommitStream,\n options: MetricsOptions = {}\n): Metrics {\n const { defaultAttribution = 'unknown', coverageThreshold = 0.7 } = options;\n\n const counts = { ai: 0, human: 0, unknown: 0 };\n const modes = { none: 0, autocomplete: 0, assisted: 0, agent: 0, unknown: 0 };\n const modeEvidence = { declared: 0, inferred: 0, none: 0 };\n for (const commit of commitStream.commits) {\n counts[commit.tags.attribution]++;\n modes[commit.tags.mode]++;\n modeEvidence[commit.tags.modeEvidence]++;\n }\n const total = commitStream.commits.length;\n const coverage = total > 0 ? (counts.ai + counts.human) / total : 0;\n\n const attribution: Attribution = {\n commitsTotal: total,\n ai: counts.ai,\n human: counts.human,\n unknown: counts.unknown,\n coverage: round(coverage, 4),\n defaultAttribution,\n coverageThreshold,\n belowThreshold: coverage < coverageThreshold,\n modes,\n modeEvidence,\n };\n\n // Cohort membership: unknown commits join a cohort only via the prior.\n // Manifest-excluded commits (release bots, merges) never do — they were\n // excluded precisely to stay out of both cohorts.\n const isExcluded = (commit: Commit) => commit.tags.sources.includes('manifest:excluded');\n const isAI = (commit: Commit) =>\n commit.tags.attribution === 'ai' ||\n (defaultAttribution === 'ai' && commit.tags.attribution === 'unknown' && !isExcluded(commit));\n const isBaseline = (commit: Commit) =>\n commit.tags.attribution === 'human' ||\n (defaultAttribution === 'human' &&\n commit.tags.attribution === 'unknown' &&\n !isExcluded(commit));\n\n const mergeRatio = calculateMergeRatio(commitStream, isAI);\n const persistence = calculatePersistence(commitStream, isAI);\n\n // Fairness context (#29, #36): cohort age and task mix\n const now = new Date();\n const aiCommits = commitStream.commits.filter(isAI);\n const baselineCommits = commitStream.commits.filter(isBaseline);\n const cohorts = {\n ai: {\n age: calculateAgeStats(aiCommits, now),\n taskMix: calculateCategoryCounts(aiCommits),\n },\n baseline: {\n age: calculateAgeStats(baselineCommits, now),\n taskMix: calculateCategoryCounts(baselineCommits),\n },\n };\n\n // No baseline cohort → no baseline, no delta. AIDA does not invent a\n // comparison out of unattributed commits.\n const baselineSize = baselineCommits.length;\n const baselineAssumed = defaultAttribution === 'human' && counts.unknown > 0;\n\n const baseline =\n baselineSize > 0\n ? {\n assumed: baselineAssumed,\n mergeRatio: calculateBaselineMergeRatio(commitStream, isBaseline),\n persistence: calculateBaselinePersistence(commitStream, isBaseline),\n }\n : null;\n\n const delta = baseline\n ? {\n mergeRatio: round(mergeRatio.mergeRatio - baseline.mergeRatio.mergeRatio, 4),\n avgPersistenceDays: round(persistence.avgDays - baseline.persistence.avgDays, 2),\n medianPersistenceDays: round(\n persistence.medianDays - baseline.persistence.medianDays,\n 2\n ),\n }\n : null;\n\n const caveats = [\n `Attribution coverage is ${(coverage * 100).toFixed(1)}%: metrics only describe commits whose provenance is known.`,\n 'Persistence is file-level, not line-level.',\n 'Persistence comparisons are only meaningful between cohorts of similar age and task mix — check the cohorts section before reading the delta.',\n 'Merge ratio: commits from all branches checked against default branch ancestry. Squash merges may undercount unmerged commits.',\n 'Time-windowed collection (--since) also windows the ancestry check: commits merged into the default branch before the window may appear unmerged.',\n 'AI tagging uses heuristic patterns; false positives/negatives possible.',\n ];\n if (baseline?.assumed) {\n caveats.push(\n `Baseline includes ${counts.unknown} unattributed commit(s) assumed human via defaultAttribution — undetected AI usage may leak into it.`\n );\n }\n if (!baseline) {\n caveats.push(\n 'No baseline: no commits are attributed as human. Set defaultAttribution to \"human\" in .aida.json if unattributed commits in this repo are human-authored.'\n );\n }\n\n return {\n generatedAt: formatISODate(new Date()),\n window: {\n since: commitStream.since,\n until: commitStream.until,\n },\n repoPath: commitStream.repoPath,\n defaultBranch: commitStream.defaultBranch,\n attribution,\n mergeRatio,\n persistence,\n cohorts,\n baseline,\n delta,\n caveats,\n };\n}\n","import { Commit, daysBetween } from '@aida-dev/core';\nimport { AgeStats, CategoryCounts, FileCategory } from './schema/metrics.js';\n\n// Cohort age (#29): persistence comparisons between cohorts of different\n// ages are misleading — old commits have had more time to accumulate\n// survival. Reporting each cohort's age lets consumers judge fairness.\nexport function calculateAgeStats(commits: Commit[], now: Date): AgeStats | null {\n if (commits.length === 0) {\n return null;\n }\n\n const ages = commits\n .map((commit) => daysBetween(new Date(commit.authorDate), now))\n .sort((a, b) => a - b);\n\n const avg = ages.reduce((sum, days) => sum + days, 0) / ages.length;\n const median =\n ages.length % 2 === 0\n ? (ages[ages.length / 2 - 1] + ages[ages.length / 2]) / 2\n : ages[Math.floor(ages.length / 2)];\n\n return {\n commits: commits.length,\n avgAgeDays: Math.round(avg * 100) / 100,\n medianAgeDays: Math.round(median * 100) / 100,\n };\n}\n\n// File categorization (#36, step 1): AI is often pointed at boilerplate,\n// tests, and migrations, which survive longer because nobody touches them.\n// Reporting each cohort's category mix shows when an AI-vs-baseline\n// comparison is apples-to-oranges. Order matters: first match wins.\nexport function categorizeFile(path: string): FileCategory {\n const lower = path.toLowerCase();\n const base = lower.split('/').pop() ?? lower;\n\n // Generated artifacts (lockfiles, changelogs, snapshots, build output)\n if (\n /^(pnpm-lock\\.yaml|package-lock\\.json|yarn\\.lock|bun\\.lockb?|composer\\.lock|cargo\\.lock|gemfile\\.lock|poetry\\.lock|changelog(\\.[a-z]+)?)$/.test(\n base\n ) ||\n /\\.(snap|min\\.js|min\\.css)$/.test(base) ||\n /(^|\\/)(dist|build|out|coverage|\\.next|node_modules)\\//.test(lower)\n ) {\n return 'generated';\n }\n\n if (\n /(^|\\/)(__tests__|__mocks__|tests?|spec|e2e|cypress)\\//.test(lower) ||\n /\\.(test|spec)\\.[a-z]+$/.test(base)\n ) {\n return 'tests';\n }\n\n if (/(^|\\/)migrations?\\//.test(lower)) {\n return 'migrations';\n }\n\n if (/\\.(md|mdx|rst|adoc|txt)$/.test(base) || /(^|\\/)docs?\\//.test(lower)) {\n return 'docs';\n }\n\n if (\n base.startsWith('.') ||\n /\\.(json|ya?ml|toml|ini|cfg|conf|env|properties)$/.test(base) ||\n /\\.config\\.[a-z]+$/.test(base) ||\n /(^|\\/)(\\.github|\\.circleci|\\.vscode|config)\\//.test(lower) ||\n /^(dockerfile|makefile|tsconfig.*|eslint.*|prettier.*)/.test(base)\n ) {\n return 'config';\n }\n\n return 'source';\n}\n\nexport function calculateCategoryCounts(commits: Commit[]): CategoryCounts | null {\n if (commits.length === 0) {\n return null;\n }\n\n const counts: CategoryCounts = {\n source: 0,\n tests: 0,\n migrations: 0,\n config: 0,\n docs: 0,\n generated: 0,\n };\n\n for (const commit of commits) {\n for (const file of commit.stats.files) {\n counts[categorizeFile(file.path)]++;\n }\n }\n\n return counts;\n}\n","import { Commit, CommitStream } from '@aida-dev/core';\nimport { CohortMergeRatio, MergeRatio } from './schema/metrics.js';\n\nfunction computeMergeRatio(commits: Commit[]): CohortMergeRatio {\n const merged = commits.filter((commit) => commit.inDefaultBranchAncestry);\n\n return {\n commitsTotal: commits.length,\n commitsMerged: merged.length,\n mergeRatio: commits.length > 0 ? merged.length / commits.length : 0,\n };\n}\n\nexport function calculateMergeRatio(\n commitStream: CommitStream,\n isTarget: (commit: Commit) => boolean = (commit) => commit.tags.attribution === 'ai'\n): MergeRatio {\n const aiCommits = commitStream.commits.filter(isTarget);\n const result = computeMergeRatio(aiCommits);\n\n return {\n aiCommitsTotal: result.commitsTotal,\n aiCommitsMerged: result.commitsMerged,\n mergeRatio: result.mergeRatio,\n };\n}\n\nexport function calculateBaselineMergeRatio(\n commitStream: CommitStream,\n isTarget: (commit: Commit) => boolean = (commit) => commit.tags.attribution === 'human'\n): CohortMergeRatio {\n const baselineCommits = commitStream.commits.filter(isTarget);\n return computeMergeRatio(baselineCommits);\n}\n","import { Commit, CommitStream, daysBetween } from '@aida-dev/core';\nimport { Persistence } from './schema/metrics.js';\n\ninterface FileLifecycle {\n path: string;\n firstTargetCommitDate: Date;\n lastSeenDate: Date;\n persistenceDays: number;\n}\n\nexport function calculatePersistence(\n commitStream: CommitStream,\n isTarget: (commit: Commit) => boolean = (commit) => commit.tags.attribution === 'ai'\n): Persistence {\n const targetCommits = commitStream.commits.filter(isTarget);\n\n if (targetCommits.length === 0) {\n return {\n commitsConsidered: 0,\n avgDays: 0,\n medianDays: 0,\n buckets: {\n d0_1: 0,\n d2_7: 0,\n d8_30: 0,\n d31_90: 0,\n d90_plus: 0,\n },\n };\n }\n\n // Group files by path and track their lifecycle\n const fileLifecycles = new Map<string, FileLifecycle>();\n\n // Sort commits by date (oldest first)\n const sortedCommits = [...commitStream.commits].sort(\n (a, b) => new Date(a.authorDate).getTime() - new Date(b.authorDate).getTime()\n );\n\n // Track first target commit per file\n for (const commit of sortedCommits) {\n if (isTarget(commit)) {\n const commitDate = new Date(commit.authorDate);\n\n for (const file of commit.stats.files) {\n if (!fileLifecycles.has(file.path)) {\n fileLifecycles.set(file.path, {\n path: file.path,\n firstTargetCommitDate: commitDate,\n lastSeenDate: commitDate,\n persistenceDays: 0,\n });\n }\n }\n }\n }\n\n // Track last seen date for each file\n for (const commit of sortedCommits) {\n const commitDate = new Date(commit.authorDate);\n\n for (const file of commit.stats.files) {\n const lifecycle = fileLifecycles.get(file.path);\n if (lifecycle) {\n // Update last seen date if file is not deleted\n if (file.status !== 'deleted') {\n lifecycle.lastSeenDate = commitDate;\n }\n }\n }\n }\n\n // Calculate persistence days for each file\n const persistenceDays: number[] = [];\n\n for (const lifecycle of fileLifecycles.values()) {\n lifecycle.persistenceDays = daysBetween(lifecycle.firstTargetCommitDate, lifecycle.lastSeenDate);\n persistenceDays.push(lifecycle.persistenceDays);\n }\n\n // Calculate statistics\n const avgDays =\n persistenceDays.length > 0\n ? persistenceDays.reduce((sum, days) => sum + days, 0) / persistenceDays.length\n : 0;\n\n const sortedDays = [...persistenceDays].sort((a, b) => a - b);\n const medianDays =\n sortedDays.length > 0\n ? sortedDays.length % 2 === 0\n ? (sortedDays[sortedDays.length / 2 - 1] + sortedDays[sortedDays.length / 2]) / 2\n : sortedDays[Math.floor(sortedDays.length / 2)]\n : 0;\n\n // Calculate buckets\n const buckets = {\n d0_1: persistenceDays.filter((days) => days <= 1).length,\n d2_7: persistenceDays.filter((days) => days >= 2 && days <= 7).length,\n d8_30: persistenceDays.filter((days) => days >= 8 && days <= 30).length,\n d31_90: persistenceDays.filter((days) => days >= 31 && days <= 90).length,\n d90_plus: persistenceDays.filter((days) => days > 90).length,\n };\n\n return {\n commitsConsidered: targetCommits.length,\n avgDays: Math.round(avgDays * 100) / 100, // Round to 2 decimal places\n medianDays: Math.round(medianDays * 100) / 100,\n buckets,\n };\n}\n\nexport function calculateBaselinePersistence(\n commitStream: CommitStream,\n isTarget: (commit: Commit) => boolean = (commit) => commit.tags.attribution === 'human'\n): Persistence {\n return calculatePersistence(commitStream, isTarget);\n}\n","import { z } from 'zod';\n\n// Attribution coverage (#34): the headline metric. Every other number in this\n// file is only as trustworthy as this block says it is.\nexport const Attribution = z.object({\n commitsTotal: z.number().int().nonnegative(),\n ai: z.number().int().nonnegative(),\n human: z.number().int().nonnegative(),\n unknown: z.number().int().nonnegative(),\n coverage: z.number().min(0).max(1), // (ai + human) / total\n defaultAttribution: z.enum(['ai', 'human', 'unknown']), // prior applied to unknown commits\n coverageThreshold: z.number().min(0).max(1),\n belowThreshold: z.boolean(),\n // Autonomy axis (#25): commit counts per mode and per mode-evidence level\n modes: z.object({\n none: z.number().int().nonnegative(),\n autocomplete: z.number().int().nonnegative(),\n assisted: z.number().int().nonnegative(),\n agent: z.number().int().nonnegative(),\n unknown: z.number().int().nonnegative(),\n }),\n modeEvidence: z.object({\n declared: z.number().int().nonnegative(),\n inferred: z.number().int().nonnegative(),\n none: z.number().int().nonnegative(),\n }),\n});\n\nexport const MergeRatio = z.object({\n aiCommitsTotal: z.number().int().nonnegative(),\n aiCommitsMerged: z.number().int().nonnegative(),\n mergeRatio: z.number().min(0).max(1),\n});\n\nexport const Persistence = z.object({\n commitsConsidered: z.number().int().nonnegative(),\n avgDays: z.number().nonnegative(),\n medianDays: z.number().nonnegative(),\n buckets: z.object({\n d0_1: z.number().int().nonnegative(),\n d2_7: z.number().int().nonnegative(),\n d8_30: z.number().int().nonnegative(),\n d31_90: z.number().int().nonnegative(),\n d90_plus: z.number().int().nonnegative(),\n }),\n});\n\n// Cohort age (#29): context for judging whether a persistence comparison\n// between cohorts is fair — older cohorts accumulate survival by default.\nexport const AgeStats = z.object({\n commits: z.number().int().nonnegative(),\n avgAgeDays: z.number().nonnegative(),\n medianAgeDays: z.number().nonnegative(),\n});\n\n// Task mix (#36): what kind of files each cohort touched. A persistence\n// comparison is only meaningful when the mixes are similar.\nexport const FileCategory = z.enum([\n 'source',\n 'tests',\n 'migrations',\n 'config',\n 'docs',\n 'generated',\n]);\n\nexport const CategoryCounts = z.object({\n source: z.number().int().nonnegative(),\n tests: z.number().int().nonnegative(),\n migrations: z.number().int().nonnegative(),\n config: z.number().int().nonnegative(),\n docs: z.number().int().nonnegative(),\n generated: z.number().int().nonnegative(),\n});\n\nexport const CohortContext = z.object({\n age: AgeStats.nullable(),\n taskMix: CategoryCounts.nullable(),\n});\n\nexport const CohortMergeRatio = z.object({\n commitsTotal: z.number().int().nonnegative(),\n commitsMerged: z.number().int().nonnegative(),\n mergeRatio: z.number().min(0).max(1),\n});\n\nexport const Baseline = z.object({\n // True when the cohort includes 'unknown' commits via defaultAttribution:\n // the baseline is an assumption, not observed attribution.\n assumed: z.boolean(),\n mergeRatio: CohortMergeRatio,\n persistence: Persistence,\n});\n\nexport const Delta = z.object({\n mergeRatio: z.number(),\n avgPersistenceDays: z.number(),\n medianPersistenceDays: z.number(),\n});\n\nexport const Metrics = z.object({\n generatedAt: z.string().datetime(),\n window: z.object({\n since: z.string().optional(),\n until: z.string().optional(),\n }),\n repoPath: z.string(),\n defaultBranch: z.string(),\n attribution: Attribution,\n mergeRatio: MergeRatio,\n persistence: Persistence,\n // Fairness context (#29, #36): age and task mix per cohort, so consumers\n // can judge whether the AI-vs-baseline comparison is apples-to-apples.\n cohorts: z.object({\n ai: CohortContext,\n baseline: CohortContext,\n }),\n // Null when no commit is attributed 'human' and no defaultAttribution prior\n // assigns the unknowns: AIDA does not invent a comparison cohort.\n baseline: Baseline.nullable(),\n delta: Delta.nullable(),\n caveats: z.array(z.string()),\n});\n\nexport type Attribution = z.infer<typeof Attribution>;\nexport type AgeStats = z.infer<typeof AgeStats>;\nexport type FileCategory = z.infer<typeof FileCategory>;\nexport type CategoryCounts = z.infer<typeof CategoryCounts>;\nexport type CohortContext = z.infer<typeof CohortContext>;\nexport type MergeRatio = z.infer<typeof MergeRatio>;\nexport type Persistence = z.infer<typeof Persistence>;\nexport type CohortMergeRatio = z.infer<typeof CohortMergeRatio>;\nexport type Baseline = z.infer<typeof Baseline>;\nexport type Delta = z.infer<typeof Delta>;\nexport type Metrics = z.infer<typeof Metrics>;\n"],"mappings":"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","names":["daysBetween"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aida-dev/metrics",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Metrics engine for AIDA (AI Development Accounting) - Merge ratio, persistence, and AI impact analysis",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
],
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"zod": "^3.22.4",
|
|
14
|
-
"@aida-dev/core": "0.
|
|
14
|
+
"@aida-dev/core": "0.10.0"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"tsup": "^8.0.0",
|