@momentiq/dark-factory-cli 0.1.0-alpha.4

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 (132) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +150 -0
  3. package/dist/adapters/_shared.d.ts +45 -0
  4. package/dist/adapters/_shared.d.ts.map +1 -0
  5. package/dist/adapters/_shared.js +200 -0
  6. package/dist/adapters/_shared.js.map +1 -0
  7. package/dist/adapters/codex-sdk.d.ts +279 -0
  8. package/dist/adapters/codex-sdk.d.ts.map +1 -0
  9. package/dist/adapters/codex-sdk.js +930 -0
  10. package/dist/adapters/codex-sdk.js.map +1 -0
  11. package/dist/adapters/critic-result-schema.d.ts +215 -0
  12. package/dist/adapters/critic-result-schema.d.ts.map +1 -0
  13. package/dist/adapters/critic-result-schema.js +153 -0
  14. package/dist/adapters/critic-result-schema.js.map +1 -0
  15. package/dist/adapters/critic.d.ts +62 -0
  16. package/dist/adapters/critic.d.ts.map +1 -0
  17. package/dist/adapters/critic.js +79 -0
  18. package/dist/adapters/critic.js.map +1 -0
  19. package/dist/adapters/cursor-sdk.d.ts +153 -0
  20. package/dist/adapters/cursor-sdk.d.ts.map +1 -0
  21. package/dist/adapters/cursor-sdk.js +818 -0
  22. package/dist/adapters/cursor-sdk.js.map +1 -0
  23. package/dist/adapters/gemini-sdk.d.ts +113 -0
  24. package/dist/adapters/gemini-sdk.d.ts.map +1 -0
  25. package/dist/adapters/gemini-sdk.js +532 -0
  26. package/dist/adapters/gemini-sdk.js.map +1 -0
  27. package/dist/adapters/grok-direct-sdk.d.ts +148 -0
  28. package/dist/adapters/grok-direct-sdk.d.ts.map +1 -0
  29. package/dist/adapters/grok-direct-sdk.js +694 -0
  30. package/dist/adapters/grok-direct-sdk.js.map +1 -0
  31. package/dist/branch-protection/audit_branch_protection.py +759 -0
  32. package/dist/branch-protection/index.d.ts +25 -0
  33. package/dist/branch-protection/index.d.ts.map +1 -0
  34. package/dist/branch-protection/index.js +70 -0
  35. package/dist/branch-protection/index.js.map +1 -0
  36. package/dist/branch-protection/spec-default.yaml +314 -0
  37. package/dist/cli.d.ts +3 -0
  38. package/dist/cli.d.ts.map +1 -0
  39. package/dist/cli.js +581 -0
  40. package/dist/cli.js.map +1 -0
  41. package/dist/cycle-doc-validator/index.d.ts +43 -0
  42. package/dist/cycle-doc-validator/index.d.ts.map +1 -0
  43. package/dist/cycle-doc-validator/index.js +69 -0
  44. package/dist/cycle-doc-validator/index.js.map +1 -0
  45. package/dist/cycle-doc-validator/validate_cycle_doc.py +1260 -0
  46. package/dist/cycle-tracker-sync/attribute_pr_cycle_ref.py +384 -0
  47. package/dist/cycle-tracker-sync/index.d.ts +20 -0
  48. package/dist/cycle-tracker-sync/index.d.ts.map +1 -0
  49. package/dist/cycle-tracker-sync/index.js +71 -0
  50. package/dist/cycle-tracker-sync/index.js.map +1 -0
  51. package/dist/cycle-tracker-sync/sync_cycle_trackers.py +1093 -0
  52. package/dist/evidence/audit-trail.d.ts +59 -0
  53. package/dist/evidence/audit-trail.d.ts.map +1 -0
  54. package/dist/evidence/audit-trail.js +283 -0
  55. package/dist/evidence/audit-trail.js.map +1 -0
  56. package/dist/evidence/index.d.ts +4 -0
  57. package/dist/evidence/index.d.ts.map +1 -0
  58. package/dist/evidence/index.js +29 -0
  59. package/dist/evidence/index.js.map +1 -0
  60. package/dist/evidence/per-sha.d.ts +13 -0
  61. package/dist/evidence/per-sha.d.ts.map +1 -0
  62. package/dist/evidence/per-sha.js +97 -0
  63. package/dist/evidence/per-sha.js.map +1 -0
  64. package/dist/evidence/quality-gates.d.ts +19 -0
  65. package/dist/evidence/quality-gates.d.ts.map +1 -0
  66. package/dist/evidence/quality-gates.js +212 -0
  67. package/dist/evidence/quality-gates.js.map +1 -0
  68. package/dist/git.d.ts +40 -0
  69. package/dist/git.d.ts.map +1 -0
  70. package/dist/git.js +414 -0
  71. package/dist/git.js.map +1 -0
  72. package/dist/glob.d.ts +4 -0
  73. package/dist/glob.d.ts.map +1 -0
  74. package/dist/glob.js +99 -0
  75. package/dist/glob.js.map +1 -0
  76. package/dist/index.d.ts +17 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +33 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/paths.d.ts +12 -0
  81. package/dist/paths.d.ts.map +1 -0
  82. package/dist/paths.js +42 -0
  83. package/dist/paths.js.map +1 -0
  84. package/dist/policy/baseline.d.ts +15 -0
  85. package/dist/policy/baseline.d.ts.map +1 -0
  86. package/dist/policy/baseline.js +115 -0
  87. package/dist/policy/baseline.js.map +1 -0
  88. package/dist/policy/config.d.ts +64 -0
  89. package/dist/policy/config.d.ts.map +1 -0
  90. package/dist/policy/config.js +363 -0
  91. package/dist/policy/config.js.map +1 -0
  92. package/dist/policy/gate.d.ts +80 -0
  93. package/dist/policy/gate.d.ts.map +1 -0
  94. package/dist/policy/gate.js +1019 -0
  95. package/dist/policy/gate.js.map +1 -0
  96. package/dist/policy/index.d.ts +7 -0
  97. package/dist/policy/index.d.ts.map +1 -0
  98. package/dist/policy/index.js +14 -0
  99. package/dist/policy/index.js.map +1 -0
  100. package/dist/policy/merge-queue.d.ts +183 -0
  101. package/dist/policy/merge-queue.d.ts.map +1 -0
  102. package/dist/policy/merge-queue.js +310 -0
  103. package/dist/policy/merge-queue.js.map +1 -0
  104. package/dist/policy/profile.d.ts +98 -0
  105. package/dist/policy/profile.d.ts.map +1 -0
  106. package/dist/policy/profile.js +156 -0
  107. package/dist/policy/profile.js.map +1 -0
  108. package/dist/policy/tdd-classifier.d.ts +18 -0
  109. package/dist/policy/tdd-classifier.d.ts.map +1 -0
  110. package/dist/policy/tdd-classifier.js +79 -0
  111. package/dist/policy/tdd-classifier.js.map +1 -0
  112. package/dist/prompt.d.ts +13 -0
  113. package/dist/prompt.d.ts.map +1 -0
  114. package/dist/prompt.js +175 -0
  115. package/dist/prompt.js.map +1 -0
  116. package/dist/report.d.ts +88 -0
  117. package/dist/report.d.ts.map +1 -0
  118. package/dist/report.js +376 -0
  119. package/dist/report.js.map +1 -0
  120. package/dist/runner.d.ts +30 -0
  121. package/dist/runner.d.ts.map +1 -0
  122. package/dist/runner.js +456 -0
  123. package/dist/runner.js.map +1 -0
  124. package/dist/security.d.ts +2 -0
  125. package/dist/security.d.ts.map +1 -0
  126. package/dist/security.js +19 -0
  127. package/dist/security.js.map +1 -0
  128. package/dist/trusted-surface/rebind.d.ts +10 -0
  129. package/dist/trusted-surface/rebind.d.ts.map +1 -0
  130. package/dist/trusted-surface/rebind.js +154 -0
  131. package/dist/trusted-surface/rebind.js.map +1 -0
  132. package/package.json +78 -0
@@ -0,0 +1,59 @@
1
+ import type { TelemetryEvent } from "@momentiq/dark-factory-schemas";
2
+ export interface TelemetrySink {
3
+ emit(event: TelemetryEvent): void;
4
+ }
5
+ export declare class FileTelemetrySink implements TelemetrySink {
6
+ private readonly path;
7
+ constructor(path: string);
8
+ emit(event: TelemetryEvent): void;
9
+ }
10
+ export declare class MemoryTelemetrySink implements TelemetrySink {
11
+ readonly events: TelemetryEvent[];
12
+ emit(event: TelemetryEvent): void;
13
+ }
14
+ export interface TelemetryStats {
15
+ totalRuns: number;
16
+ errorRuns: number;
17
+ bypasses: number;
18
+ blocks: number;
19
+ passes: number;
20
+ approvedCount: number;
21
+ changesRequestedCount: number;
22
+ byCritic: Record<string, CriticStats>;
23
+ medianDurationMs: number | null;
24
+ retry: RetrySummary;
25
+ }
26
+ export interface RetrySummary {
27
+ firstAttemptSuccess: number;
28
+ oneRetrySuccess: number;
29
+ twoPlusRetrySuccess: number;
30
+ exhaustedByErrorCode: Record<string, number>;
31
+ totalRetryAttempts: number;
32
+ }
33
+ export interface CriticStats {
34
+ starts: number;
35
+ finishes: number;
36
+ errors: number;
37
+ approved: number;
38
+ changesRequested: number;
39
+ totalFindings: number;
40
+ totalBlockers: number;
41
+ totalHigh: number;
42
+ medianDurationMs: number | null;
43
+ }
44
+ export declare function readTelemetryEvents(path: string): TelemetryEvent[];
45
+ export declare function summarizeTelemetry(events: TelemetryEvent[]): TelemetryStats;
46
+ export interface CriticAgreement {
47
+ comparedCommits: number;
48
+ agreedCommits: number;
49
+ disagreementsByPattern: Record<string, number>;
50
+ comparedCriticIds: string[];
51
+ }
52
+ export interface QuorumStats {
53
+ totalAggregateEvents: number;
54
+ byReason: Record<string, number>;
55
+ quorumUnmetByCritic: Record<string, number>;
56
+ }
57
+ export declare function computeQuorumStats(events: TelemetryEvent[]): QuorumStats;
58
+ export declare function computeCriticAgreement(events: TelemetryEvent[]): CriticAgreement;
59
+ //# sourceMappingURL=audit-trail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-trail.d.ts","sourceRoot":"","sources":["../../src/evidence/audit-trail.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErE,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;CACnC;AAED,qBAAa,iBAAkB,YAAW,aAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,MAAM;IAGzC,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;CAGlC;AAED,qBAAa,mBAAoB,YAAW,aAAa;IACvD,QAAQ,CAAC,MAAM,EAAE,cAAc,EAAE,CAAM;IACvC,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;CAGlC;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACtC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAMhC,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAG3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAI5B,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAI7C,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAalE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,cAAc,CAmK3E;AAuCD,MAAM,WAAW,eAAe;IAE9B,eAAe,EAAE,MAAM,CAAC;IAExB,aAAa,EAAE,MAAM,CAAC;IAMtB,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAG/C,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAwBD,MAAM,WAAW,WAAW;IAE1B,oBAAoB,EAAE,MAAM,CAAC;IAG7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAQjC,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7C;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,WAAW,CAmBxE;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,eAAe,CAgDhF"}
@@ -0,0 +1,283 @@
1
+ import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ export class FileTelemetrySink {
4
+ path;
5
+ constructor(path) {
6
+ this.path = path;
7
+ mkdirSync(dirname(path), { recursive: true });
8
+ }
9
+ emit(event) {
10
+ appendFileSync(this.path, `${JSON.stringify(event)}\n`, "utf8");
11
+ }
12
+ }
13
+ export class MemoryTelemetrySink {
14
+ events = [];
15
+ emit(event) {
16
+ this.events.push(event);
17
+ }
18
+ }
19
+ export function readTelemetryEvents(path) {
20
+ if (!existsSync(path))
21
+ return [];
22
+ const out = [];
23
+ for (const line of readFileSync(path, "utf8").split("\n")) {
24
+ const t = line.trim();
25
+ if (!t)
26
+ continue;
27
+ try {
28
+ out.push(JSON.parse(t));
29
+ }
30
+ catch {
31
+ // skip corrupt line
32
+ }
33
+ }
34
+ return out;
35
+ }
36
+ export function summarizeTelemetry(events) {
37
+ const byCritic = new Map();
38
+ const allDurations = [];
39
+ let totalRuns = 0;
40
+ let errorRuns = 0;
41
+ let bypasses = 0;
42
+ let blocks = 0;
43
+ let passes = 0;
44
+ let approvedCount = 0;
45
+ let changesRequestedCount = 0;
46
+ // Cycle 322.1 — retry counters. Segmented on the `retryCount` field
47
+ // attached to terminal events (`critic_run_finished` for success;
48
+ // the last `critic_run_error` of a run for exhausted-retries).
49
+ // Intermediate `critic_run_error` events (those followed by another
50
+ // attempt of the SAME run) count toward `totalRetryAttempts` and
51
+ // are NOT counted as separate errored runs.
52
+ let firstAttemptSuccess = 0;
53
+ let oneRetrySuccess = 0;
54
+ let twoPlusRetrySuccess = 0;
55
+ const exhaustedByErrorCode = {};
56
+ let totalRetryAttempts = 0;
57
+ const errorsByRun = new Map();
58
+ function runKey(e) {
59
+ // commit is the most stable component — pre-322.1 runs without
60
+ // criticId or runId still group by commit. Add criticId to
61
+ // disambiguate the multi-critic future (Cycle 322.2/322.3).
62
+ return `${e.criticId ?? "?"}|${e.commit ?? "?"}`;
63
+ }
64
+ for (const e of events) {
65
+ if (e.event === "critic_run_started" && e.criticId) {
66
+ const stats = ensureStats(byCritic, e.criticId);
67
+ stats.starts++;
68
+ totalRuns++;
69
+ }
70
+ else if (e.event === "critic_run_finished" && e.criticId) {
71
+ const stats = ensureStats(byCritic, e.criticId);
72
+ stats.finishes++;
73
+ if (e.verdict === "APPROVED") {
74
+ stats.approved++;
75
+ approvedCount++;
76
+ }
77
+ else if (e.verdict === "CHANGES_REQUESTED") {
78
+ stats.changesRequested++;
79
+ changesRequestedCount++;
80
+ }
81
+ stats.totalFindings += e.findingCount ?? 0;
82
+ stats.totalBlockers += e.blockerCount ?? 0;
83
+ stats.totalHigh += e.highCount ?? 0;
84
+ if (typeof e.durationMs === "number") {
85
+ allDurations.push(e.durationMs);
86
+ }
87
+ const rc = typeof e.retryCount === "number" ? e.retryCount : 0;
88
+ if (rc === 0)
89
+ firstAttemptSuccess++;
90
+ else if (rc === 1)
91
+ oneRetrySuccess++;
92
+ else
93
+ twoPlusRetrySuccess++;
94
+ // NOTE: do NOT increment `totalRetryAttempts` here. The
95
+ // second-pass bucket loop derives the retry count from the
96
+ // intermediate-error events themselves (one per real retry).
97
+ // Adding `rc` here would double-count those same retries. See
98
+ // the bucket loop below for the single source of truth.
99
+ }
100
+ else if (e.event === "critic_run_error" && e.criticId) {
101
+ const key = runKey(e);
102
+ const bucket = errorsByRun.get(key) ?? [];
103
+ bucket.push(e);
104
+ errorsByRun.set(key, bucket);
105
+ }
106
+ else if (e.event === "gate_blocked") {
107
+ blocks++;
108
+ }
109
+ else if (e.event === "gate_passed") {
110
+ passes++;
111
+ }
112
+ else if (e.event === "gate_bypassed") {
113
+ bypasses++;
114
+ }
115
+ }
116
+ // Second pass: turn per-run error buckets into terminal-error stats
117
+ // without double-counting intermediate retry events. The terminal
118
+ // event for a run is the one with the highest `retryCount` (or the
119
+ // sole event for pre-322.1 runs without retryCount).
120
+ for (const [key, bucket] of errorsByRun) {
121
+ // Sort by retryCount asc; the terminal failure is the last one
122
+ // when retries are exhausted (because the loop never produced a
123
+ // critic_run_finished for this key).
124
+ const criticId = key.split("|", 1)[0];
125
+ const finishedForKey = events.some((e) => e.event === "critic_run_finished" && runKey(e) === key);
126
+ if (finishedForKey) {
127
+ // A finished event exists — every error in this bucket was
128
+ // intermediate (followed by another attempt that succeeded).
129
+ // Count those as retry attempts, NOT errored runs.
130
+ totalRetryAttempts += bucket.length;
131
+ continue;
132
+ }
133
+ // No finished event — the LAST error in the bucket is the
134
+ // terminal failure. Earlier errors are retry attempts.
135
+ bucket.sort((a, b) => (a.retryCount ?? 0) - (b.retryCount ?? 0));
136
+ const terminal = bucket[bucket.length - 1];
137
+ if (!terminal)
138
+ continue;
139
+ const intermediates = bucket.length - 1;
140
+ if (intermediates > 0)
141
+ totalRetryAttempts += intermediates;
142
+ if (criticId) {
143
+ const stats = ensureStats(byCritic, criticId);
144
+ stats.errors++;
145
+ }
146
+ errorRuns++;
147
+ const codeKey = typeof terminal.errorCode === "string" && terminal.errorCode.length > 0
148
+ ? terminal.errorCode
149
+ : "unknown";
150
+ exhaustedByErrorCode[codeKey] = (exhaustedByErrorCode[codeKey] ?? 0) + 1;
151
+ }
152
+ for (const [criticId, stats] of byCritic) {
153
+ // Per-critic median: filter durations to events from THIS critic only.
154
+ // Earlier loop body destructured `[, stats]` and dropped the criticId,
155
+ // so `durs` collected every critic's durations and assigned the same
156
+ // global median to each entry. (Cycle 3 #10)
157
+ const durs = events
158
+ .filter((e) => e.event === "critic_run_finished" &&
159
+ e.criticId === criticId &&
160
+ typeof e.durationMs === "number")
161
+ .map((e) => e.durationMs);
162
+ stats.medianDurationMs = median(durs);
163
+ }
164
+ return {
165
+ totalRuns,
166
+ errorRuns,
167
+ bypasses,
168
+ blocks,
169
+ passes,
170
+ approvedCount,
171
+ changesRequestedCount,
172
+ byCritic: Object.fromEntries(byCritic),
173
+ medianDurationMs: median(allDurations),
174
+ retry: {
175
+ firstAttemptSuccess,
176
+ oneRetrySuccess,
177
+ twoPlusRetrySuccess,
178
+ exhaustedByErrorCode,
179
+ totalRetryAttempts,
180
+ },
181
+ };
182
+ }
183
+ function ensureStats(map, key) {
184
+ let s = map.get(key);
185
+ if (!s) {
186
+ s = {
187
+ starts: 0,
188
+ finishes: 0,
189
+ errors: 0,
190
+ approved: 0,
191
+ changesRequested: 0,
192
+ totalFindings: 0,
193
+ totalBlockers: 0,
194
+ totalHigh: 0,
195
+ medianDurationMs: null,
196
+ };
197
+ map.set(key, s);
198
+ }
199
+ return s;
200
+ }
201
+ function median(values) {
202
+ if (values.length === 0)
203
+ return null;
204
+ const sorted = [...values].sort((a, b) => a - b);
205
+ const mid = Math.floor(sorted.length / 2);
206
+ if (sorted.length % 2 === 0) {
207
+ return Math.round(((sorted[mid - 1] ?? 0) + (sorted[mid] ?? 0)) / 2);
208
+ }
209
+ return sorted[mid] ?? null;
210
+ }
211
+ export function computeQuorumStats(events) {
212
+ let totalAggregateEvents = 0;
213
+ const byReason = {};
214
+ const quorumUnmetByCritic = {};
215
+ for (const e of events) {
216
+ if (e.event !== "review_finished")
217
+ continue;
218
+ const reason = e.aggregateReason;
219
+ if (!reason)
220
+ continue;
221
+ totalAggregateEvents++;
222
+ byReason[reason] = (byReason[reason] ?? 0) + 1;
223
+ if (reason === "quorum_unmet" && e.criticCompletionStates) {
224
+ for (const [id, state] of Object.entries(e.criticCompletionStates)) {
225
+ if (state === "errored" || state === "pending") {
226
+ quorumUnmetByCritic[id] = (quorumUnmetByCritic[id] ?? 0) + 1;
227
+ }
228
+ }
229
+ }
230
+ }
231
+ return { totalAggregateEvents, byReason, quorumUnmetByCritic };
232
+ }
233
+ export function computeCriticAgreement(events) {
234
+ // Group `critic_run_finished` events by commit. Within each commit,
235
+ // dedupe on criticId so a retry-success (which may emit one finished
236
+ // event after retries) doesn't double-weight that critic.
237
+ const finishedByCommit = new Map();
238
+ for (const e of events) {
239
+ if (e.event !== "critic_run_finished")
240
+ continue;
241
+ if (!e.commit || !e.criticId || !e.verdict)
242
+ continue;
243
+ let m = finishedByCommit.get(e.commit);
244
+ if (!m) {
245
+ m = new Map();
246
+ finishedByCommit.set(e.commit, m);
247
+ }
248
+ // The LAST verdict wins per (commit, criticId) — successful retries
249
+ // may produce earlier failed-error events, but only the success is
250
+ // tagged with a verdict (failed events have no verdict field).
251
+ m.set(e.criticId, e.verdict);
252
+ }
253
+ let comparedCommits = 0;
254
+ let agreedCommits = 0;
255
+ const disagreementsByPattern = {};
256
+ const allCriticIds = new Set();
257
+ for (const verdicts of finishedByCommit.values()) {
258
+ if (verdicts.size < 2)
259
+ continue;
260
+ comparedCommits++;
261
+ for (const id of verdicts.keys())
262
+ allCriticIds.add(id);
263
+ const distinct = new Set(verdicts.values());
264
+ if (distinct.size === 1) {
265
+ agreedCommits++;
266
+ continue;
267
+ }
268
+ // Build a sorted-by-criticId pattern string so the same disagreement
269
+ // (regardless of stream-order) hashes into the same bucket.
270
+ const pattern = [...verdicts.entries()]
271
+ .sort((a, b) => a[0].localeCompare(b[0]))
272
+ .map(([id, v]) => `${id}:${v}`)
273
+ .join(" / ");
274
+ disagreementsByPattern[pattern] = (disagreementsByPattern[pattern] ?? 0) + 1;
275
+ }
276
+ return {
277
+ comparedCommits,
278
+ agreedCommits,
279
+ disagreementsByPattern,
280
+ comparedCriticIds: [...allCriticIds].sort(),
281
+ };
282
+ }
283
+ //# sourceMappingURL=audit-trail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-trail.js","sourceRoot":"","sources":["../../src/evidence/audit-trail.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { parseCommitTrailers, getTrailer, perShaQualityGatePath, collectChangedPaths, QUALITY_GATES_SUBDIR, type CommitTrailers, } from "./per-sha.js";
2
+ export { runQualityGates, readQualityGateEvidence, type QualityGateRunOptions, type ReadEvidenceResult, } from "./quality-gates.js";
3
+ export { FileTelemetrySink, MemoryTelemetrySink, readTelemetryEvents, summarizeTelemetry, computeQuorumStats, computeCriticAgreement, type TelemetrySink, type TelemetryStats, type RetrySummary, type CriticStats, type CriticAgreement, type QuorumStats, } from "./audit-trail.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/evidence/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,mBAAmB,EACnB,UAAU,EACV,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAa5B,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACtB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,WAAW,GACjB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,29 @@
1
+ // Service #4 — Per-SHA Evidence Store
2
+ // Service #8 — Audit / Compliance Trail
3
+ //
4
+ // Phase C boundary added service #4 (per-SHA quality-gate evidence
5
+ // path helpers + the quality-gates runner). Phase D boundary adds
6
+ // service #8 (the `_runs.ndjson` audit/compliance trail) — the
7
+ // runtime telemetry sink + the read/summarize helpers that back
8
+ // `make agent-review-stats` / `df audit stats`.
9
+ //
10
+ // Note: `per-sha.ts` currently also exports `parseCommitTrailers` and
11
+ // `collectChangedPaths` which logically belong under `policy/` and `git/`
12
+ // respectively. Whole-file move is intentional per Phase C extraction
13
+ // brief (preserve behavior + minimize import churn). Tracked for cleanup
14
+ // in a follow-up tech-debt issue.
15
+ export { parseCommitTrailers, getTrailer, perShaQualityGatePath, collectChangedPaths, QUALITY_GATES_SUBDIR, } from "./per-sha.js";
16
+ export { runQualityGates, readQualityGateEvidence, } from "./quality-gates.js";
17
+ // Service #8 — Audit / Compliance Trail (Phase D boundary).
18
+ //
19
+ // `_runs.ndjson` is the structural audit log: every critic run, every
20
+ // gate verdict, every bypass invocation appends here. Operators read
21
+ // it via `df audit stats` (or the legacy `make agent-review-stats`).
22
+ //
23
+ // The sink classes (FileTelemetrySink, MemoryTelemetrySink) are the
24
+ // write side; readTelemetryEvents + summarizeTelemetry +
25
+ // computeQuorumStats + computeCriticAgreement are the read/analyze
26
+ // side. Keeping them in the same module ensures the schema cannot
27
+ // drift between writer and reader.
28
+ export { FileTelemetrySink, MemoryTelemetrySink, readTelemetryEvents, summarizeTelemetry, computeQuorumStats, computeCriticAgreement, } from "./audit-trail.js";
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/evidence/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,wCAAwC;AACxC,EAAE;AACF,mEAAmE;AACnE,kEAAkE;AAClE,+DAA+D;AAC/D,gEAAgE;AAChE,gDAAgD;AAChD,EAAE;AACF,sEAAsE;AACtE,0EAA0E;AAC1E,sEAAsE;AACtE,yEAAyE;AACzE,kCAAkC;AAElC,OAAO,EACL,mBAAmB,EACnB,UAAU,EACV,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,GAErB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,uBAAuB,GAGxB,MAAM,oBAAoB,CAAC;AAE5B,4DAA4D;AAC5D,EAAE;AACF,sEAAsE;AACtE,qEAAqE;AACrE,qEAAqE;AACrE,EAAE;AACF,oEAAoE;AACpE,yDAAyD;AACzD,mEAAmE;AACnE,kEAAkE;AAClE,mCAAmC;AACnC,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,GAOvB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,13 @@
1
+ export interface CommitTrailers {
2
+ readonly trailers: Record<string, string>;
3
+ readonly hasTrailerBlock: boolean;
4
+ }
5
+ export declare function parseCommitTrailers(message: string): CommitTrailers;
6
+ export declare function getTrailer(trailers: CommitTrailers, key: string): string | undefined;
7
+ export declare function perShaQualityGatePath(artifactRoot: string, artifactDir: string, sha: string): string;
8
+ export declare const QUALITY_GATES_SUBDIR = "quality-gates";
9
+ export declare function collectChangedPaths(files: ReadonlyArray<{
10
+ path: string;
11
+ oldPath?: string;
12
+ }>): string[];
13
+ //# sourceMappingURL=per-sha.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"per-sha.d.ts","sourceRoot":"","sources":["../../src/evidence/per-sha.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,cAAc;IAM7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAI1C,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;CACnC;AAID,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAqDnE;AAID,wBAAgB,UAAU,CACxB,QAAQ,EAAE,cAAc,EACxB,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,CAEpB;AAOD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,GACV,MAAM,CAER;AAED,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AASpD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACvD,MAAM,EAAE,CAOV"}
@@ -0,0 +1,97 @@
1
+ // Commit-trailer parsing and per-SHA evidence file path helpers.
2
+ // Trailers (per git-interpret-trailers semantics) carry human-supplied
3
+ // overrides into the gate: a developer who deliberately ships a
4
+ // production-only change can attach `Tdd-Justification: <reason>` and the
5
+ // TDD classifier returns `justified` instead of `block`. The keys are
6
+ // case-insensitive; whitespace around values is trimmed.
7
+ import { resolve } from "node:path";
8
+ const TRAILER_LINE = /^([A-Za-z][A-Za-z0-9._-]*)\s*:\s*(.*)$/;
9
+ export function parseCommitTrailers(message) {
10
+ const trailers = {};
11
+ if (!message)
12
+ return { trailers, hasTrailerBlock: false };
13
+ // Normalize line endings and trim trailing whitespace so a message
14
+ // ending with "\n\n" still surfaces its trailer block.
15
+ const lines = message.replace(/\r\n?/g, "\n").split("\n");
16
+ while (lines.length > 0 && (lines[lines.length - 1] ?? "").trim() === "") {
17
+ lines.pop();
18
+ }
19
+ if (lines.length === 0)
20
+ return { trailers, hasTrailerBlock: false };
21
+ // Walk backwards from the end, collecting consecutive lines that look
22
+ // like trailers. The block ends at the first blank line OR the first
23
+ // non-trailer line. This matches git-interpret-trailers' behavior: the
24
+ // last paragraph is treated as a trailer block iff every line in it is
25
+ // a trailer or a continuation (line starting with whitespace).
26
+ const collected = [];
27
+ for (let i = lines.length - 1; i >= 0; i--) {
28
+ const line = lines[i] ?? "";
29
+ if (line.trim() === "")
30
+ break;
31
+ collected.unshift(line);
32
+ }
33
+ if (collected.length === 0)
34
+ return { trailers, hasTrailerBlock: false };
35
+ // Every non-continuation line in the candidate block must match the
36
+ // trailer pattern; otherwise this is a regular paragraph and trailers
37
+ // are NOT extracted. This guards against parsing free-prose paragraphs
38
+ // (e.g., "Reviewed by Alice. Tested locally.") as trailers.
39
+ let hasAnyTrailer = false;
40
+ for (const line of collected) {
41
+ if (line.startsWith(" ") || line.startsWith("\t"))
42
+ continue;
43
+ if (TRAILER_LINE.test(line)) {
44
+ hasAnyTrailer = true;
45
+ continue;
46
+ }
47
+ // First non-trailer, non-continuation line invalidates the block.
48
+ return { trailers, hasTrailerBlock: false };
49
+ }
50
+ if (!hasAnyTrailer)
51
+ return { trailers, hasTrailerBlock: false };
52
+ for (const line of collected) {
53
+ const match = line.match(TRAILER_LINE);
54
+ if (!match)
55
+ continue;
56
+ const rawKey = match[1] ?? "";
57
+ const value = (match[2] ?? "").trim();
58
+ const key = rawKey.toLowerCase();
59
+ if (key in trailers)
60
+ continue; // first occurrence wins
61
+ if (value.length === 0)
62
+ continue; // empty value is no override
63
+ trailers[key] = value;
64
+ }
65
+ return { trailers, hasTrailerBlock: true };
66
+ }
67
+ // Return a recognized trailer value by case-insensitive key, or undefined.
68
+ // Callers should compare against the canonical lowercased key.
69
+ export function getTrailer(trailers, key) {
70
+ return trailers.trailers[key.toLowerCase()];
71
+ }
72
+ // Per-SHA evidence file path under <artifactRoot>/<artifactDir>/quality-gates/<sha>.json.
73
+ // Centralized so quality-gates.ts, gate.ts, and the runner all agree on the
74
+ // canonical layout. The legacy `validation.resultFile` ("latest.json") is
75
+ // maintained as a back-compat write target during the 318.2 → 318.4
76
+ // migration window, but consumers should prefer the per-SHA path.
77
+ export function perShaQualityGatePath(artifactRoot, artifactDir, sha) {
78
+ return resolve(artifactRoot, artifactDir, "quality-gates", `${sha}.json`);
79
+ }
80
+ export const QUALITY_GATES_SUBDIR = "quality-gates";
81
+ // Flatten `ChangedFile[]` (or anything shaped like `{path, oldPath?}`)
82
+ // into a path list that includes both the new `path` and (when present)
83
+ // the rename/copy `oldPath`. Used by every gate-time path consumer so a
84
+ // route-classified or TDD-classified file matches on EITHER side of a
85
+ // rename. Centralized here (no git/runner/cli dependencies) so the
86
+ // three former inline loops in runner.ts / gate.ts / cli.ts cannot
87
+ // drift. (Codex P2 follow-up on d46b8be7.)
88
+ export function collectChangedPaths(files) {
89
+ const out = [];
90
+ for (const f of files) {
91
+ out.push(f.path);
92
+ if (f.oldPath && f.oldPath !== f.path)
93
+ out.push(f.oldPath);
94
+ }
95
+ return out;
96
+ }
97
+ //# sourceMappingURL=per-sha.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"per-sha.js","sourceRoot":"","sources":["../../src/evidence/per-sha.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { LoadedConfig } from "../policy/config.js";
2
+ import { type QualityGateEvidence } from "@momentiq/dark-factory-schemas";
3
+ export interface QualityGateRunOptions {
4
+ loaded: LoadedConfig;
5
+ commit: string;
6
+ cwd?: string;
7
+ commands?: string[];
8
+ signal?: AbortSignal;
9
+ excerptLines?: number;
10
+ routeId?: string;
11
+ }
12
+ export declare function runQualityGates(options: QualityGateRunOptions): Promise<QualityGateEvidence>;
13
+ export interface ReadEvidenceResult {
14
+ evidence: QualityGateEvidence | null;
15
+ path: string;
16
+ stale: boolean;
17
+ }
18
+ export declare function readQualityGateEvidence(loaded: LoadedConfig, commit: string): Promise<ReadEvidenceResult>;
19
+ //# sourceMappingURL=quality-gates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality-gates.d.ts","sourceRoot":"","sources":["../../src/evidence/quality-gates.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAiBxD,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,gCAAgC,CAAC;AAIxC,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IAMtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA2DlG;AAgBD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,CAAC,CA4B7B"}