projscan 3.0.5 → 3.0.7

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 (48) hide show
  1. package/README.md +37 -23
  2. package/dist/cli/commands/dogfood.js +16 -0
  3. package/dist/cli/commands/dogfood.js.map +1 -1
  4. package/dist/cli/commands/feedback.d.ts +1 -0
  5. package/dist/cli/commands/feedback.js +176 -0
  6. package/dist/cli/commands/feedback.js.map +1 -0
  7. package/dist/cli/commands/trial.d.ts +1 -0
  8. package/dist/cli/commands/trial.js +81 -0
  9. package/dist/cli/commands/trial.js.map +1 -0
  10. package/dist/cli/index.js +4 -0
  11. package/dist/cli/index.js.map +1 -1
  12. package/dist/core/dogfood.d.ts +2 -1
  13. package/dist/core/dogfood.js +290 -10
  14. package/dist/core/dogfood.js.map +1 -1
  15. package/dist/core/feedback.d.ts +12 -0
  16. package/dist/core/feedback.js +213 -0
  17. package/dist/core/feedback.js.map +1 -0
  18. package/dist/core/releaseEvidence.js +5 -1
  19. package/dist/core/releaseEvidence.js.map +1 -1
  20. package/dist/core/start.js +9 -0
  21. package/dist/core/start.js.map +1 -1
  22. package/dist/core/trial.d.ts +6 -0
  23. package/dist/core/trial.js +134 -0
  24. package/dist/core/trial.js.map +1 -0
  25. package/dist/grammars/tree-sitter-swift.wasm +0 -0
  26. package/dist/index.d.ts +3 -1
  27. package/dist/index.js +2 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/projscan-sbom.cdx.json +6 -6
  30. package/dist/tool-manifest.json +2 -2
  31. package/dist/types.d.ts +169 -0
  32. package/dist/utils/formatSupport.d.ts +5 -0
  33. package/dist/utils/formatSupport.js +5 -0
  34. package/dist/utils/formatSupport.js.map +1 -1
  35. package/package.json +5 -3
  36. package/public/.well-known/security.txt +6 -0
  37. package/public/brand/baseframe-labs/mark-dark-on-dark.png +0 -0
  38. package/public/brand/baseframe-labs/mark-dark.png +0 -0
  39. package/public/brand/baseframe-labs/mark-dark.svg +1 -0
  40. package/public/brand/baseframe-labs/mark-light-on-white.png +0 -0
  41. package/public/brand/baseframe-labs/mark-light.png +0 -0
  42. package/public/brand/baseframe-labs/mark-light.svg +1 -0
  43. package/public/brand/baseframe-labs/wordmark-dark-on-dark.png +0 -0
  44. package/public/brand/baseframe-labs/wordmark-dark.png +0 -0
  45. package/public/brand/baseframe-labs/wordmark-dark.svg +1 -0
  46. package/public/brand/baseframe-labs/wordmark-light-on-white.png +0 -0
  47. package/public/brand/baseframe-labs/wordmark-light.png +0 -0
  48. package/public/brand/baseframe-labs/wordmark-light.svg +1 -0
@@ -1,6 +1,7 @@
1
- import type { DogfoodReport } from '../types.js';
1
+ import type { DogfoodFeedbackInput, DogfoodReport } from '../types.js';
2
2
  export interface ComputeDogfoodOptions {
3
3
  repos?: string[];
4
4
  targetRepoCount?: number;
5
+ feedback?: DogfoodFeedbackInput;
5
6
  }
6
7
  export declare function computeDogfoodReport(rootPath: string, options?: ComputeDogfoodOptions): Promise<DogfoodReport>;
@@ -1,4 +1,5 @@
1
1
  import path from 'node:path';
2
+ import { MIN_REPEAT_FEEDBACK_PRS, MIN_REPEAT_FEEDBACK_REPOS } from './feedback.js';
2
3
  import { computeEvidencePack } from './releaseEvidence.js';
3
4
  import { computeStartReport } from './start.js';
4
5
  const DEFAULT_TARGET_REPO_COUNT = 3;
@@ -6,36 +7,54 @@ const FEEDBACK_QUESTIONS = [
6
7
  'Did the PR comment save 10-20 minutes?',
7
8
  'What was missing or noisy?',
8
9
  'Which owner or command should have been clearer?',
10
+ 'Minutes saved: 0, 5, 10, 20+?',
11
+ 'Did projscan prevent a risky edit or missed review step?',
9
12
  ];
13
+ const FEEDBACK_INIT_COMMAND = 'projscan feedback init --output .projscan-feedback.json';
14
+ const FEEDBACK_CAPTURE_COMMAND = 'projscan feedback add --file .projscan-feedback.json --repo <repo> --pr <url> --reviewer <handle> --useful true --minutes-saved 10';
15
+ const DOGFOOD_WITH_FEEDBACK_COMMAND = 'projscan dogfood --repo <repo-a> --repo <repo-b> --repo <repo-c> --feedback .projscan-feedback.json --format json';
16
+ const MIN_USEFUL_REVIEWER_RESPONSES = 3;
17
+ const MIN_AVERAGE_MINUTES_SAVED = 10;
10
18
  export async function computeDogfoodReport(rootPath, options = {}) {
11
19
  const targetRepoCount = normalizeTargetRepoCount(options.targetRepoCount);
12
20
  const repos = normalizeRepos(rootPath, options.repos);
13
- const results = await Promise.all(repos.map((repoPath) => evaluateRepo(repoPath)));
21
+ const feedback = normalizeFeedback(options.feedback);
22
+ const results = await Promise.all(repos.map((repoPath) => evaluateRepo(repoPath, feedback)));
14
23
  const totals = summarizeTotals(results);
24
+ const marketValidation = buildMarketValidation(results, targetRepoCount);
15
25
  return {
16
26
  schemaVersion: 1,
17
27
  readOnly: true,
18
28
  rootPath,
19
29
  targetRepoCount,
20
- summary: summarizeDogfood(results.length, targetRepoCount, totals),
30
+ summary: summarizeDogfood(results.length, targetRepoCount, totals, marketValidation),
21
31
  repos: results,
22
32
  totals,
23
- suggestedNextActions: buildDogfoodActions(results.length, targetRepoCount),
33
+ marketValidation,
34
+ suggestedNextActions: buildDogfoodActions(results.length, targetRepoCount, marketValidation),
24
35
  };
25
36
  }
26
- async function evaluateRepo(repoPath) {
37
+ async function evaluateRepo(repoPath, feedback) {
27
38
  const [start, evidence] = await Promise.all([
28
39
  computeStartReport(repoPath, { mode: 'before_merge', maxTasks: 4, maxRisks: 5 }),
29
40
  computeEvidencePack(repoPath, { includePrComment: true, maxFindings: 3 }),
30
41
  ]);
42
+ const name = path.basename(repoPath) || repoPath;
31
43
  const prComment = evidence.prComment ?? '';
32
44
  const prCommentReady = evidence.prCommentValidation?.status === 'pass' && prComment.includes('### Developer Feedback');
33
45
  const repeatUseReady = start.adoptionLoop?.cadence === 'every_pr' && (start.adoptionLoop.nextCommands.length ?? 0) >= 3;
34
46
  const mcpReady = start.evidence.mcpReady;
35
- const gaps = buildGaps({ prCommentReady, repeatUseReady, mcpReady, healthScore: start.evidence.healthScore });
47
+ const validation = summarizeRepoFeedback(feedbackForRepo(feedback, repoPath, name));
48
+ const gaps = buildGaps({
49
+ prCommentReady,
50
+ repeatUseReady,
51
+ mcpReady,
52
+ healthScore: start.evidence.healthScore,
53
+ validation,
54
+ });
36
55
  return {
37
56
  path: repoPath,
38
- name: path.basename(repoPath) || repoPath,
57
+ name,
39
58
  status: statusFromGaps(gaps, start.evidence.healthScore),
40
59
  healthScore: start.evidence.healthScore,
41
60
  mcpReady,
@@ -44,10 +63,14 @@ async function evaluateRepo(repoPath) {
44
63
  verdict: evidence.verdict,
45
64
  gaps,
46
65
  feedbackQuestions: [...FEEDBACK_QUESTIONS],
66
+ validation,
47
67
  nextCommands: [
48
68
  'projscan init team --team platform',
49
69
  'projscan evidence-pack --pr-comment',
50
70
  'projscan preflight --mode before_merge --format json',
71
+ FEEDBACK_INIT_COMMAND,
72
+ FEEDBACK_CAPTURE_COMMAND,
73
+ DOGFOOD_WITH_FEEDBACK_COMMAND,
51
74
  ],
52
75
  };
53
76
  }
@@ -60,6 +83,44 @@ function normalizeRepos(rootPath, repos) {
60
83
  const values = repos && repos.length > 0 ? repos : [rootPath];
61
84
  return [...new Set(values.map((value) => path.resolve(rootPath, value)))];
62
85
  }
86
+ function normalizeFeedback(input) {
87
+ return Array.isArray(input?.responses) ? input.responses : [];
88
+ }
89
+ function feedbackForRepo(feedback, repoPath, repoName) {
90
+ const normalizedPath = normalizeMatchValue(repoPath);
91
+ const normalizedName = normalizeMatchValue(repoName);
92
+ return feedback.filter((response) => {
93
+ const repo = normalizeMatchValue(response.repo ?? '');
94
+ if (!repo)
95
+ return false;
96
+ return matchesRepoKey(repo, normalizedName, normalizedPath);
97
+ });
98
+ }
99
+ function matchesRepoKey(repo, repoName, repoPath) {
100
+ if (repo === repoName || repo === repoPath || repoPath.endsWith('/' + repo))
101
+ return true;
102
+ if (repoName.startsWith(repo + '-') || repoName.endsWith('-' + repo))
103
+ return true;
104
+ if (repoName.includes('-' + repo + '-'))
105
+ return true;
106
+ if (repoPath.includes('/' + repo + '-') || repoPath.includes('/' + repo + '/'))
107
+ return true;
108
+ return repoPath.includes('-' + repo + '-');
109
+ }
110
+ function summarizeRepoFeedback(feedback) {
111
+ return {
112
+ feedbackResponses: feedback.length,
113
+ usefulResponses: feedback.filter((response) => response.useful === true).length,
114
+ prRefs: cleanSignals(feedback.map((response) => response.pr ?? '')),
115
+ minutesSaved: sumNumbers(feedback.map((response) => response.minutesSaved)),
116
+ preventedBadEdits: feedback.filter((response) => response.preventedBadEdit === true).length,
117
+ ownerRoutingClear: feedback.filter((response) => response.ownerRoutingClear === true).length,
118
+ nextCommandClear: feedback.filter((response) => response.nextCommandClear === true).length,
119
+ falsePositiveRules: cleanSignals(feedback.flatMap((response) => response.falsePositiveRules ?? [])),
120
+ missingSignals: cleanSignals(feedback.flatMap((response) => response.missingSignals ?? [])),
121
+ noisyFindings: cleanSignals(feedback.flatMap((response) => response.noisyFindings ?? [])),
122
+ };
123
+ }
63
124
  function buildGaps(input) {
64
125
  const gaps = [];
65
126
  if (input.healthScore < 80)
@@ -70,6 +131,12 @@ function buildGaps(input) {
70
131
  gaps.push('PR comment is missing required usefulness sections');
71
132
  if (!input.repeatUseReady)
72
133
  gaps.push('repeat-use adoption loop is missing');
134
+ if (input.validation.falsePositiveRules.length > 0) {
135
+ gaps.push('reviewer reported false-positive rule(s): ' + input.validation.falsePositiveRules.join(', '));
136
+ }
137
+ if (input.validation.missingSignals.length > 0) {
138
+ gaps.push('reviewer reported missing signal(s): ' + input.validation.missingSignals.join('; '));
139
+ }
73
140
  return gaps;
74
141
  }
75
142
  function statusFromGaps(gaps, healthScore) {
@@ -88,18 +155,167 @@ function summarizeTotals(repos) {
88
155
  prCommentReady: repos.filter((repo) => repo.prCommentReady).length,
89
156
  repeatUseReady: repos.filter((repo) => repo.repeatUseReady).length,
90
157
  mcpReady: repos.filter((repo) => repo.mcpReady).length,
158
+ usefulFeedback: repos.reduce((sum, repo) => sum + repo.validation.usefulResponses, 0),
159
+ minutesSaved: repos.reduce((sum, repo) => sum + repo.validation.minutesSaved, 0),
160
+ preventedBadEdits: repos.reduce((sum, repo) => sum + repo.validation.preventedBadEdits, 0),
161
+ falsePositiveReports: repos.reduce((sum, repo) => sum + repo.validation.falsePositiveRules.length, 0),
162
+ };
163
+ }
164
+ function buildMarketValidation(repos, targetRepoCount) {
165
+ const responseCount = repos.reduce((sum, repo) => sum + repo.validation.feedbackResponses, 0);
166
+ const usefulResponses = repos.reduce((sum, repo) => sum + repo.validation.usefulResponses, 0);
167
+ const totalMinutesSaved = repos.reduce((sum, repo) => sum + repo.validation.minutesSaved, 0);
168
+ const preventedBadEdits = repos.reduce((sum, repo) => sum + repo.validation.preventedBadEdits, 0);
169
+ const ownerRoutingClear = repos.reduce((sum, repo) => sum + repo.validation.ownerRoutingClear, 0);
170
+ const nextCommandClear = repos.reduce((sum, repo) => sum + repo.validation.nextCommandClear, 0);
171
+ const falsePositive = {
172
+ totalReports: repos.reduce((sum, repo) => sum + repo.validation.falsePositiveRules.length, 0),
173
+ noisyRules: countSignals(repos.flatMap((repo) => repo.validation.falsePositiveRules), 'rule'),
174
+ missingSignals: countSignals(repos.flatMap((repo) => repo.validation.missingSignals), 'signal'),
175
+ noisyFindings: countSignals(repos.flatMap((repo) => repo.validation.noisyFindings), 'finding'),
176
+ };
177
+ const repoCoverage = {
178
+ target: targetRepoCount,
179
+ evaluated: repos.length,
180
+ targetMet: repos.length >= targetRepoCount,
91
181
  };
182
+ const firstPr = {
183
+ readyRepos: repos.filter((repo) => repo.prCommentReady).length,
184
+ repeatUseReadyRepos: repos.filter((repo) => repo.repeatUseReady).length,
185
+ requiredFeedbackQuestions: [...FEEDBACK_QUESTIONS],
186
+ };
187
+ const feedback = {
188
+ responses: responseCount,
189
+ usefulResponses,
190
+ usefulnessRate: responseCount > 0 ? round(usefulResponses / responseCount) : 0,
191
+ preventedBadEdits,
192
+ ownerRoutingClear,
193
+ nextCommandClear,
194
+ minutesSaved: {
195
+ total: totalMinutesSaved,
196
+ average: responseCount > 0 ? round(totalMinutesSaved / responseCount) : 0,
197
+ max: Math.max(0, ...repos.map((repo) => repo.validation.minutesSaved)),
198
+ },
199
+ };
200
+ const repeatUse = summarizeRepeatUse(repos);
201
+ const value = {
202
+ averageMinutesSaved: feedback.minutesSaved.average,
203
+ requiredAverageMinutesSaved: MIN_AVERAGE_MINUTES_SAVED,
204
+ preventedBadEdits,
205
+ ready: feedback.minutesSaved.average >= MIN_AVERAGE_MINUTES_SAVED || preventedBadEdits > 0,
206
+ };
207
+ const status = marketStatus({
208
+ targetMet: repoCoverage.targetMet,
209
+ responses: responseCount,
210
+ usefulResponses,
211
+ falsePositiveReports: falsePositive.totalReports,
212
+ valueReady: value.ready,
213
+ repeatUseReady: repeatUse.ready,
214
+ });
215
+ const summary = summarizeMarketValidation(status, repoCoverage.evaluated, targetRepoCount, feedback, falsePositive.totalReports, value, repeatUse);
216
+ return {
217
+ status,
218
+ summary,
219
+ repoCoverage,
220
+ feedback,
221
+ falsePositive,
222
+ firstPr,
223
+ value,
224
+ repeatUse,
225
+ websiteProof: buildWebsiteProof(repos, feedback, falsePositive.totalReports, status, repeatUse),
226
+ };
227
+ }
228
+ function marketStatus(input) {
229
+ if (!input.targetMet)
230
+ return 'needs_more_repos';
231
+ if (input.responses === 0)
232
+ return 'needs_feedback';
233
+ if (input.usefulResponses < MIN_USEFUL_REVIEWER_RESPONSES)
234
+ return 'needs_tuning';
235
+ if (input.falsePositiveReports > input.usefulResponses)
236
+ return 'needs_tuning';
237
+ if (!input.valueReady)
238
+ return 'needs_tuning';
239
+ if (!input.repeatUseReady)
240
+ return 'needs_tuning';
241
+ return 'proven';
92
242
  }
93
- function summarizeDogfood(reposEvaluated, targetRepoCount, totals) {
243
+ function summarizeMarketValidation(status, evaluated, target, feedback, falsePositiveReports, value, repeatUse) {
244
+ const base = evaluated + '/' + target + ' repo target; ' + feedback.responses + ' reviewer response(s); ' + feedback.minutesSaved.total + ' minutes saved; avg ' + value.averageMinutesSaved + '/' + value.requiredAverageMinutesSaved + ' min target; ' + feedback.preventedBadEdits + ' risky edit(s) prevented; ' + falsePositiveReports + ' false-positive report(s); ' + repeatUse.repeatedRepos + ' repo(s) with repeat PR feedback';
245
+ if (status === 'proven')
246
+ return 'market validation proven: ' + base;
247
+ if (status === 'needs_more_repos')
248
+ return 'market validation needs more repos: ' + base;
249
+ if (status === 'needs_feedback')
250
+ return 'market validation needs reviewer feedback: ' + base;
251
+ return 'market validation needs tuning: ' + base;
252
+ }
253
+ function buildWebsiteProof(repos, feedback, falsePositiveReports, status, repeatUse) {
254
+ const repoCount = repos.length;
255
+ const headline = buildWebsiteProofHeadline(status, repoCount);
256
+ const metrics = [
257
+ repoCount + ' real repo(s) evaluated',
258
+ feedback.responses + ' reviewer response(s)',
259
+ feedback.minutesSaved.total + ' minutes saved',
260
+ feedback.preventedBadEdits + ' risky edits prevented',
261
+ repeatUse.repeatedRepos + ' repo(s) with repeat PR feedback',
262
+ falsePositiveReports + ' false-positive report(s) tracked',
263
+ ];
264
+ const claimBullet = status === 'proven'
265
+ ? 'Website claims can cite measured minutes saved and risky edits prevented instead of generic scanner claims.'
266
+ : 'Website claims should stay provisional until repo coverage, useful feedback, and false-positive tuning are ready.';
267
+ const bullets = [
268
+ 'Generated PR comments were validated before posting.',
269
+ 'Reviewer feedback is captured as structured dogfood evidence.',
270
+ 'Repeat PR use is measured separately from first-PR usefulness.',
271
+ 'False positives, missing signals, owner clarity, and next-command clarity are visible in one report.',
272
+ claimBullet,
273
+ ];
274
+ const markdown = [
275
+ '## Market Validation Proof',
276
+ '',
277
+ '**Status:** ' + status,
278
+ '**Headline:** ' + headline,
279
+ '',
280
+ '### Metrics',
281
+ ...metrics.map((metric) => '- ' + metric),
282
+ '',
283
+ '### What To Show On The Website',
284
+ ...bullets.map((bullet) => '- ' + bullet),
285
+ ].join('\\n');
286
+ return { headline, metrics, bullets, markdown };
287
+ }
288
+ function buildWebsiteProofHeadline(status, repoCount) {
289
+ if (status === 'proven')
290
+ return 'projscan proved useful across ' + repoCount + ' real repo(s)';
291
+ if (status === 'needs_more_repos')
292
+ return 'projscan needs more real-repo validation before public proof';
293
+ if (status === 'needs_feedback')
294
+ return 'projscan needs reviewer feedback before usefulness proof';
295
+ return 'projscan needs tuning before usefulness proof';
296
+ }
297
+ function summarizeDogfood(reposEvaluated, targetRepoCount, totals, marketValidation) {
94
298
  const target = reposEvaluated >= targetRepoCount ? 'target met' : 'needs more repos';
95
- return 'dogfood: ' + reposEvaluated + ' repo(s) evaluated (' + target + '); ' + totals.prCommentReady + '/' + reposEvaluated + ' PR comments ready; ' + totals.repeatUseReady + '/' + reposEvaluated + ' repeat-use loops ready';
299
+ return 'dogfood: ' + reposEvaluated + ' repo(s) evaluated (' + target + '); ' + totals.prCommentReady + '/' + reposEvaluated + ' PR comments ready; ' + totals.repeatUseReady + '/' + reposEvaluated + ' repeat-use loops ready; validation=' + marketValidation.status;
96
300
  }
97
- function buildDogfoodActions(reposEvaluated, targetRepoCount) {
301
+ function buildDogfoodActions(reposEvaluated, targetRepoCount, marketValidation) {
98
302
  const actions = [
99
303
  {
100
304
  label: 'Run dogfood against a real team repo',
101
305
  command: 'projscan dogfood --repo <path-to-repo> --format json',
102
306
  },
307
+ {
308
+ label: 'Initialize structured reviewer feedback',
309
+ command: FEEDBACK_INIT_COMMAND,
310
+ },
311
+ {
312
+ label: 'Capture first PR feedback as structured evidence',
313
+ command: FEEDBACK_CAPTURE_COMMAND,
314
+ },
315
+ {
316
+ label: 'Roll feedback into dogfood validation',
317
+ command: DOGFOOD_WITH_FEEDBACK_COMMAND,
318
+ },
103
319
  {
104
320
  label: 'Capture first PR feedback',
105
321
  command: 'projscan evidence-pack --pr-comment',
@@ -111,6 +327,70 @@ function buildDogfoodActions(reposEvaluated, targetRepoCount) {
111
327
  command: 'projscan dogfood --repo <repo-a> --repo <repo-b> --repo <repo-c> --format json',
112
328
  });
113
329
  }
114
- return actions;
330
+ if (marketValidation.status === 'needs_feedback') {
331
+ actions.unshift({
332
+ label: 'Ask real reviewers for first-PR usefulness feedback',
333
+ command: FEEDBACK_CAPTURE_COMMAND,
334
+ });
335
+ }
336
+ if (marketValidation.status === 'needs_tuning') {
337
+ actions.unshift({
338
+ label: 'Tune noisy rules before expanding rollout',
339
+ command: 'projscan memory stable --format json',
340
+ });
341
+ }
342
+ return dedupeActions(actions);
343
+ }
344
+ function dedupeActions(actions) {
345
+ const seen = new Set();
346
+ const result = [];
347
+ for (const action of actions) {
348
+ const key = action.command ?? action.label;
349
+ if (seen.has(key))
350
+ continue;
351
+ seen.add(key);
352
+ result.push(action);
353
+ }
354
+ return result;
355
+ }
356
+ function summarizeRepeatUse(repos) {
357
+ const distinctPrs = countDistinct(repos.flatMap((repo) => repo.validation.prRefs));
358
+ const repeatedRepos = repos.filter((repo) => countDistinct(repo.validation.prRefs) >= 2).length;
359
+ return {
360
+ distinctPrs,
361
+ repeatedRepos,
362
+ requiredDistinctPrs: MIN_REPEAT_FEEDBACK_PRS,
363
+ requiredRepeatedRepos: MIN_REPEAT_FEEDBACK_REPOS,
364
+ ready: distinctPrs >= MIN_REPEAT_FEEDBACK_PRS && repeatedRepos >= MIN_REPEAT_FEEDBACK_REPOS,
365
+ };
366
+ }
367
+ function countDistinct(values) {
368
+ return new Set(values.map(normalizeMatchValue).filter(Boolean)).size;
369
+ }
370
+ function countSignals(values, key) {
371
+ const counts = new Map();
372
+ for (const value of cleanSignals(values))
373
+ counts.set(value, (counts.get(value) ?? 0) + 1);
374
+ return [...counts.entries()]
375
+ .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
376
+ .map(([value, count]) => ({ [key]: value, count }));
377
+ }
378
+ function cleanSignals(values) {
379
+ return values
380
+ .map((value) => value.trim())
381
+ .filter((value) => value.length > 0 && value.toLowerCase() !== 'none');
382
+ }
383
+ function sumNumbers(values) {
384
+ return values.reduce((sum, value) => {
385
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < 0)
386
+ return sum;
387
+ return sum + value;
388
+ }, 0);
389
+ }
390
+ function normalizeMatchValue(value) {
391
+ return value.replace(/\\/g, '/').replace(/\/$/, '').trim().toLowerCase();
392
+ }
393
+ function round(value) {
394
+ return Math.round(value * 100) / 100;
115
395
  }
116
396
  //# sourceMappingURL=dogfood.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dogfood.js","sourceRoot":"","sources":["../../src/core/dogfood.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dogfood.js","sourceRoot":"","sources":["../../src/core/dogfood.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { DogfoodFeedbackInput, DogfoodFeedbackResponse, FeedbackSummaryReport, FeedbackTemplateResult } from '../types.js';
2
+ export interface CreateFeedbackTemplateOptions {
3
+ force?: boolean;
4
+ }
5
+ export declare const FEEDBACK_ARTIFACT_VERSION = 1;
6
+ export declare const MIN_REPEAT_FEEDBACK_PRS = 3;
7
+ export declare const MIN_REPEAT_FEEDBACK_REPOS = 1;
8
+ export declare function createFeedbackTemplate(filePath: string, options?: CreateFeedbackTemplateOptions): Promise<FeedbackTemplateResult>;
9
+ export declare function readFeedbackFile(filePath: string): Promise<DogfoodFeedbackInput>;
10
+ export declare function addFeedbackResponse(filePath: string, response: DogfoodFeedbackResponse): Promise<DogfoodFeedbackInput>;
11
+ export declare function summarizeFeedbackFile(filePath: string): Promise<FeedbackSummaryReport>;
12
+ export declare function summarizeFeedback(responses: DogfoodFeedbackResponse[], filePath?: string): FeedbackSummaryReport;
@@ -0,0 +1,213 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ export const FEEDBACK_ARTIFACT_VERSION = 1;
4
+ export const MIN_REPEAT_FEEDBACK_PRS = 3;
5
+ export const MIN_REPEAT_FEEDBACK_REPOS = 1;
6
+ const FEEDBACK_QUESTIONS = [
7
+ 'Did the generated PR comment save 10-20 minutes?',
8
+ 'How many minutes did projscan save on this PR?',
9
+ 'Did projscan prevent a risky edit or missed review step?',
10
+ 'Were the owner route and next command clear?',
11
+ 'Which rule was noisy, false-positive, or missing a signal?',
12
+ ];
13
+ export async function createFeedbackTemplate(filePath, options = {}) {
14
+ const resolved = path.resolve(filePath);
15
+ if (!options.force) {
16
+ try {
17
+ await fs.access(resolved);
18
+ throw new Error('Feedback file already exists at ' + resolved + '. Pass --force to overwrite it.');
19
+ }
20
+ catch (error) {
21
+ if (!isNodeErrorCode(error, 'ENOENT'))
22
+ throw error;
23
+ }
24
+ }
25
+ const artifact = buildTemplate(resolved);
26
+ await fs.mkdir(path.dirname(resolved), { recursive: true });
27
+ await fs.writeFile(resolved, JSON.stringify(toStoredFeedback(artifact), null, 2) + '\n', 'utf8');
28
+ return artifact;
29
+ }
30
+ export async function readFeedbackFile(filePath) {
31
+ const resolved = path.resolve(filePath);
32
+ const raw = await fs.readFile(resolved, 'utf8');
33
+ const parsed = JSON.parse(raw);
34
+ return normalizeFeedbackInput(parsed);
35
+ }
36
+ export async function addFeedbackResponse(filePath, response) {
37
+ const resolved = path.resolve(filePath);
38
+ let artifact;
39
+ try {
40
+ artifact = await readFeedbackFile(resolved);
41
+ }
42
+ catch (error) {
43
+ if (!isNodeErrorCode(error, 'ENOENT'))
44
+ throw error;
45
+ artifact = toStoredFeedback(buildTemplate(resolved));
46
+ }
47
+ const normalized = normalizeFeedbackResponse(response);
48
+ artifact.responses.push(normalized);
49
+ await fs.mkdir(path.dirname(resolved), { recursive: true });
50
+ await fs.writeFile(resolved, JSON.stringify(artifact, null, 2) + '\n', 'utf8');
51
+ return artifact;
52
+ }
53
+ export async function summarizeFeedbackFile(filePath) {
54
+ const resolved = path.resolve(filePath);
55
+ const artifact = await readFeedbackFile(resolved);
56
+ return summarizeFeedback(artifact.responses, resolved);
57
+ }
58
+ export function summarizeFeedback(responses, filePath = '.projscan-feedback.json') {
59
+ const usefulResponses = responses.filter((response) => response.useful === true).length;
60
+ const minutes = responses.map((response) => response.minutesSaved);
61
+ const totalMinutes = sumNumbers(minutes);
62
+ const distinctRepos = countDistinct(responses.map((response) => response.repo));
63
+ const distinctPrs = countDistinct(responses.map((response) => response.pr));
64
+ const repeatedRepos = countRepeatedRepos(responses);
65
+ const falsePositiveRules = cleanSignals(responses.flatMap((response) => response.falsePositiveRules ?? []));
66
+ const missingSignals = cleanSignals(responses.flatMap((response) => response.missingSignals ?? []));
67
+ const noisyFindings = cleanSignals(responses.flatMap((response) => response.noisyFindings ?? []));
68
+ return {
69
+ schemaVersion: FEEDBACK_ARTIFACT_VERSION,
70
+ path: filePath,
71
+ responses: responses.length,
72
+ usefulResponses,
73
+ distinctRepos,
74
+ distinctPrs,
75
+ minutesSaved: {
76
+ total: totalMinutes,
77
+ average: responses.length > 0 ? round(totalMinutes / responses.length) : 0,
78
+ max: Math.max(0, ...responses.map((response) => saneNumber(response.minutesSaved))),
79
+ },
80
+ preventedBadEdits: responses.filter((response) => response.preventedBadEdit === true).length,
81
+ ownerRoutingClear: responses.filter((response) => response.ownerRoutingClear === true).length,
82
+ nextCommandClear: responses.filter((response) => response.nextCommandClear === true).length,
83
+ repeatUse: {
84
+ distinctPrs,
85
+ repeatedRepos,
86
+ requiredDistinctPrs: MIN_REPEAT_FEEDBACK_PRS,
87
+ requiredRepeatedRepos: MIN_REPEAT_FEEDBACK_REPOS,
88
+ ready: distinctPrs >= MIN_REPEAT_FEEDBACK_PRS && repeatedRepos >= MIN_REPEAT_FEEDBACK_REPOS,
89
+ },
90
+ falsePositive: {
91
+ totalReports: falsePositiveRules.length,
92
+ noisyRules: countSignals(falsePositiveRules, 'rule'),
93
+ missingSignals: countSignals(missingSignals, 'signal'),
94
+ noisyFindings: countSignals(noisyFindings, 'finding'),
95
+ },
96
+ nextDogfoodCommand: 'projscan dogfood --feedback ' + filePath + ' --format json',
97
+ };
98
+ }
99
+ function buildTemplate(filePath) {
100
+ return {
101
+ schemaVersion: FEEDBACK_ARTIFACT_VERSION,
102
+ path: filePath,
103
+ createdAt: new Date().toISOString(),
104
+ questions: [...FEEDBACK_QUESTIONS],
105
+ instructions: [
106
+ 'Record one response per real PR review.',
107
+ 'Use the same repo with multiple PR URLs when a team comes back and uses projscan again.',
108
+ 'Run projscan feedback summary --file ' + filePath + ' --format json before dogfood.',
109
+ 'Feed this artifact into projscan dogfood with --feedback ' + filePath + '.',
110
+ ],
111
+ responses: [],
112
+ };
113
+ }
114
+ function toStoredFeedback(template) {
115
+ return {
116
+ schemaVersion: template.schemaVersion,
117
+ questions: template.questions,
118
+ responses: template.responses,
119
+ };
120
+ }
121
+ function normalizeFeedbackInput(input) {
122
+ if (!input || typeof input !== 'object') {
123
+ return { schemaVersion: FEEDBACK_ARTIFACT_VERSION, questions: [...FEEDBACK_QUESTIONS], responses: [] };
124
+ }
125
+ const raw = input;
126
+ return {
127
+ schemaVersion: raw.schemaVersion === FEEDBACK_ARTIFACT_VERSION ? FEEDBACK_ARTIFACT_VERSION : FEEDBACK_ARTIFACT_VERSION,
128
+ questions: Array.isArray(raw.questions) ? raw.questions.filter((question) => typeof question === 'string') : [...FEEDBACK_QUESTIONS],
129
+ responses: Array.isArray(raw.responses) ? raw.responses.map(normalizeFeedbackResponse) : [],
130
+ };
131
+ }
132
+ function normalizeFeedbackResponse(response) {
133
+ const input = response && typeof response === 'object' ? response : {};
134
+ const normalized = {};
135
+ const repo = cleanString(input.repo);
136
+ const pr = cleanString(input.pr);
137
+ const reviewer = cleanString(input.reviewer);
138
+ const note = cleanString(input.note);
139
+ if (repo)
140
+ normalized.repo = repo;
141
+ if (pr)
142
+ normalized.pr = pr;
143
+ if (reviewer)
144
+ normalized.reviewer = reviewer;
145
+ if (typeof input.useful === 'boolean')
146
+ normalized.useful = input.useful;
147
+ if (typeof input.preventedBadEdit === 'boolean')
148
+ normalized.preventedBadEdit = input.preventedBadEdit;
149
+ if (typeof input.ownerRoutingClear === 'boolean')
150
+ normalized.ownerRoutingClear = input.ownerRoutingClear;
151
+ if (typeof input.nextCommandClear === 'boolean')
152
+ normalized.nextCommandClear = input.nextCommandClear;
153
+ if (note)
154
+ normalized.note = note;
155
+ normalized.minutesSaved = saneNumber(input.minutesSaved);
156
+ normalized.falsePositiveRules = cleanSignals(input.falsePositiveRules ?? []);
157
+ normalized.missingSignals = cleanSignals(input.missingSignals ?? []);
158
+ normalized.noisyFindings = cleanSignals(input.noisyFindings ?? []);
159
+ return normalized;
160
+ }
161
+ function countDistinct(values) {
162
+ return new Set(values.map((value) => normalizeKey(value ?? '')).filter(Boolean)).size;
163
+ }
164
+ function countRepeatedRepos(responses) {
165
+ const prsByRepo = new Map();
166
+ for (const response of responses) {
167
+ const repo = normalizeKey(response.repo ?? '');
168
+ const pr = normalizeKey(response.pr ?? '');
169
+ if (!repo || !pr)
170
+ continue;
171
+ if (!prsByRepo.has(repo))
172
+ prsByRepo.set(repo, new Set());
173
+ prsByRepo.get(repo)?.add(pr);
174
+ }
175
+ return [...prsByRepo.values()].filter((prs) => prs.size >= 2).length;
176
+ }
177
+ function countSignals(values, key) {
178
+ const counts = new Map();
179
+ for (const value of cleanSignals(values))
180
+ counts.set(value, (counts.get(value) ?? 0) + 1);
181
+ return [...counts.entries()]
182
+ .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
183
+ .map(([value, count]) => ({ [key]: value, count }));
184
+ }
185
+ function isNodeErrorCode(error, code) {
186
+ return typeof error === 'object' && error !== null && 'code' in error && error.code === code;
187
+ }
188
+ function cleanSignals(values) {
189
+ return values
190
+ .map((value) => value.trim())
191
+ .filter((value) => value.length > 0 && value.toLowerCase() !== 'none');
192
+ }
193
+ function cleanString(value) {
194
+ if (typeof value !== 'string')
195
+ return undefined;
196
+ const trimmed = value.trim();
197
+ return trimmed.length > 0 ? trimmed : undefined;
198
+ }
199
+ function normalizeKey(value) {
200
+ return value.replace(/\\/g, '/').replace(/\/$/, '').trim().toLowerCase();
201
+ }
202
+ function sumNumbers(values) {
203
+ return values.reduce((sum, value) => sum + saneNumber(value), 0);
204
+ }
205
+ function saneNumber(value) {
206
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < 0)
207
+ return 0;
208
+ return value;
209
+ }
210
+ function round(value) {
211
+ return Math.round(value * 100) / 100;
212
+ }
213
+ //# sourceMappingURL=feedback.js.map