@boshu2/vibe-check 1.6.2 → 1.8.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.
Files changed (156) hide show
  1. package/.agents/bundles/actionable-coaching-plan-2025-12-02.md +209 -0
  2. package/.agents/bundles/automatic-learning-cadence-plan-2025-12-02.md +1297 -0
  3. package/.agents/bundles/automatic-learning-cadence-research-2025-12-02.md +481 -0
  4. package/.agents/bundles/dashboard-data-quality-plan.md +458 -0
  5. package/.agents/bundles/rating-scoring-alignment-plan.md +427 -0
  6. package/.agents/bundles/rpi-session-capture-plan-2025-12-02.md +693 -0
  7. package/.agents/bundles/rpi-session-capture-research-2025-12-02.md +433 -0
  8. package/.agents/bundles/session-integration-plan-2025-12-02.md +144 -0
  9. package/.agents/plans/git-forensics-enhancement-2025-12-05.md +493 -0
  10. package/.claude/skills/typescript-review.md +152 -0
  11. package/CHANGELOG.md +53 -0
  12. package/CLAUDE.md +79 -3
  13. package/Makefile +160 -0
  14. package/README.md +141 -155
  15. package/SECURITY.md +5 -1
  16. package/assets/logo-dark.svg +47 -0
  17. package/assets/logo.svg +47 -0
  18. package/claude-progress.json +54 -4
  19. package/claude-progress.txt +114 -0
  20. package/dashboard/app.js +699 -66
  21. package/dashboard/chart.min.js +20 -0
  22. package/dashboard/dashboard-data.js +764 -0
  23. package/dashboard/dashboard-data.json +182 -71
  24. package/dashboard/index.html +139 -14
  25. package/dashboard/styles.css +579 -4
  26. package/dist/analyzers/patterns.d.ts +62 -0
  27. package/dist/analyzers/patterns.d.ts.map +1 -0
  28. package/dist/analyzers/patterns.js +103 -0
  29. package/dist/analyzers/patterns.js.map +1 -0
  30. package/dist/analyzers/quality.d.ts +58 -0
  31. package/dist/analyzers/quality.d.ts.map +1 -0
  32. package/dist/analyzers/quality.js +114 -0
  33. package/dist/analyzers/quality.js.map +1 -0
  34. package/dist/analyzers/sessions.d.ts +45 -0
  35. package/dist/analyzers/sessions.d.ts.map +1 -0
  36. package/dist/analyzers/sessions.js +123 -0
  37. package/dist/analyzers/sessions.js.map +1 -0
  38. package/dist/cli.js +5 -1
  39. package/dist/cli.js.map +1 -1
  40. package/dist/commands/analyze.d.ts.map +1 -1
  41. package/dist/commands/analyze.js +43 -2
  42. package/dist/commands/analyze.js.map +1 -1
  43. package/dist/commands/dashboard.js +4 -1
  44. package/dist/commands/dashboard.js.map +1 -1
  45. package/dist/commands/forensics.d.ts +29 -0
  46. package/dist/commands/forensics.d.ts.map +1 -0
  47. package/dist/commands/forensics.js +213 -0
  48. package/dist/commands/forensics.js.map +1 -0
  49. package/dist/commands/index.d.ts +5 -1
  50. package/dist/commands/index.d.ts.map +1 -1
  51. package/dist/commands/index.js +13 -3
  52. package/dist/commands/index.js.map +1 -1
  53. package/dist/commands/insights.d.ts +3 -0
  54. package/dist/commands/insights.d.ts.map +1 -0
  55. package/dist/commands/insights.js +120 -0
  56. package/dist/commands/insights.js.map +1 -0
  57. package/dist/commands/learn.d.ts +3 -0
  58. package/dist/commands/learn.d.ts.map +1 -0
  59. package/dist/commands/learn.js +161 -0
  60. package/dist/commands/learn.js.map +1 -0
  61. package/dist/commands/lesson.d.ts +8 -0
  62. package/dist/commands/lesson.d.ts.map +1 -0
  63. package/dist/commands/lesson.js +206 -0
  64. package/dist/commands/lesson.js.map +1 -0
  65. package/dist/commands/pipeline.d.ts +3 -0
  66. package/dist/commands/pipeline.d.ts.map +1 -0
  67. package/dist/commands/pipeline.js +485 -0
  68. package/dist/commands/pipeline.js.map +1 -0
  69. package/dist/commands/profile.d.ts +0 -1
  70. package/dist/commands/profile.d.ts.map +1 -1
  71. package/dist/commands/profile.js +3 -206
  72. package/dist/commands/profile.js.map +1 -1
  73. package/dist/commands/session.d.ts +51 -0
  74. package/dist/commands/session.d.ts.map +1 -0
  75. package/dist/commands/session.js +599 -0
  76. package/dist/commands/session.js.map +1 -0
  77. package/dist/commands/sessions.d.ts +20 -0
  78. package/dist/commands/sessions.d.ts.map +1 -0
  79. package/dist/commands/sessions.js +201 -0
  80. package/dist/commands/sessions.js.map +1 -0
  81. package/dist/commands/watch.d.ts.map +1 -1
  82. package/dist/commands/watch.js +48 -7
  83. package/dist/commands/watch.js.map +1 -1
  84. package/dist/gamification/index.d.ts +1 -3
  85. package/dist/gamification/index.d.ts.map +1 -1
  86. package/dist/gamification/index.js +2 -5
  87. package/dist/gamification/index.js.map +1 -1
  88. package/dist/gamification/pattern-memory.d.ts +1 -1
  89. package/dist/gamification/pattern-memory.d.ts.map +1 -1
  90. package/dist/gamification/pattern-memory.js.map +1 -1
  91. package/dist/gamification/profile.d.ts +2 -2
  92. package/dist/gamification/profile.d.ts.map +1 -1
  93. package/dist/gamification/profile.js +2 -15
  94. package/dist/gamification/profile.js.map +1 -1
  95. package/dist/gamification/types.d.ts +8 -2
  96. package/dist/gamification/types.d.ts.map +1 -1
  97. package/dist/gamification/types.js.map +1 -1
  98. package/dist/insights/index.d.ts.map +1 -1
  99. package/dist/insights/index.js +16 -4
  100. package/dist/insights/index.js.map +1 -1
  101. package/dist/insights/types.d.ts +14 -0
  102. package/dist/insights/types.d.ts.map +1 -1
  103. package/dist/learning/cadence.d.ts +15 -0
  104. package/dist/learning/cadence.d.ts.map +1 -0
  105. package/dist/learning/cadence.js +130 -0
  106. package/dist/learning/cadence.js.map +1 -0
  107. package/dist/learning/index.d.ts +19 -0
  108. package/dist/learning/index.d.ts.map +1 -0
  109. package/dist/learning/index.js +35 -0
  110. package/dist/learning/index.js.map +1 -0
  111. package/dist/learning/lessons-storage.d.ts +48 -0
  112. package/dist/learning/lessons-storage.d.ts.map +1 -0
  113. package/dist/learning/lessons-storage.js +266 -0
  114. package/dist/learning/lessons-storage.js.map +1 -0
  115. package/dist/learning/lessons-types.d.ts +83 -0
  116. package/dist/learning/lessons-types.d.ts.map +1 -0
  117. package/dist/learning/lessons-types.js +15 -0
  118. package/dist/learning/lessons-types.js.map +1 -0
  119. package/dist/learning/nudges.d.ts +20 -0
  120. package/dist/learning/nudges.d.ts.map +1 -0
  121. package/dist/learning/nudges.js +68 -0
  122. package/dist/learning/nudges.js.map +1 -0
  123. package/dist/learning/retrospective.d.ts +27 -0
  124. package/dist/learning/retrospective.d.ts.map +1 -0
  125. package/dist/learning/retrospective.js +184 -0
  126. package/dist/learning/retrospective.js.map +1 -0
  127. package/dist/learning/storage.d.ts +44 -0
  128. package/dist/learning/storage.d.ts.map +1 -0
  129. package/dist/learning/storage.js +194 -0
  130. package/dist/learning/storage.js.map +1 -0
  131. package/dist/learning/surfacing.d.ts +36 -0
  132. package/dist/learning/surfacing.d.ts.map +1 -0
  133. package/dist/learning/surfacing.js +255 -0
  134. package/dist/learning/surfacing.js.map +1 -0
  135. package/dist/learning/synthesis.d.ts +17 -0
  136. package/dist/learning/synthesis.d.ts.map +1 -0
  137. package/dist/learning/synthesis.js +293 -0
  138. package/dist/learning/synthesis.js.map +1 -0
  139. package/dist/learning/types.d.ts +60 -0
  140. package/dist/learning/types.d.ts.map +1 -0
  141. package/dist/learning/types.js +17 -0
  142. package/dist/learning/types.js.map +1 -0
  143. package/dist/storage/index.d.ts +1 -0
  144. package/dist/storage/index.d.ts.map +1 -1
  145. package/dist/storage/index.js +11 -1
  146. package/dist/storage/index.js.map +1 -1
  147. package/dist/storage/spiral-history.d.ts +62 -0
  148. package/dist/storage/spiral-history.d.ts.map +1 -0
  149. package/dist/storage/spiral-history.js +265 -0
  150. package/dist/storage/spiral-history.js.map +1 -0
  151. package/docs/ARCHITECTURE.md +2 -10
  152. package/docs/GAMIFICATION.md +19 -266
  153. package/docs/METRICS.md +528 -0
  154. package/docs/VIBE-ECOSYSTEM.md +12 -78
  155. package/feature-list.json +141 -68
  156. package/package.json +1 -1
@@ -0,0 +1,427 @@
1
+ # Rating/Scoring Alignment Implementation Plan
2
+
3
+ **Type:** Plan
4
+ **Created:** 2025-11-30
5
+ **Depends On:** In-session analysis
6
+ **Loop:** Middle (bridges research to implementation)
7
+ **Tags:** scoring, dashboard, UX, metrics
8
+
9
+ ---
10
+
11
+ ## Overview
12
+
13
+ The dashboard currently has two scoring systems that measure different things:
14
+ 1. **vibeScore (0-100%)** - Pattern-based from semantic-free metrics
15
+ 2. **Metric-based overall rating** - Quality-based from 5 semantic metrics
16
+
17
+ The current quick fix aligned badges to vibeScore, but the metric-based rating may be a better predictor of coding health. This plan implements a dual-display approach that shows both meaningfully.
18
+
19
+ ## Problem Analysis
20
+
21
+ ### What vibeScore Measures (Pattern Health)
22
+ - `fileChurn`: Files touched repeatedly (instability signal)
23
+ - `timeSpiral`: Commit timing patterns (spiral detection)
24
+ - `velocityAnomaly`: Deviation from your baseline velocity
25
+ - `codeStability`: Lines surviving vs deleted (thrashing)
26
+
27
+ **Good for:** Detecting workflow patterns, identifying when you're struggling
28
+
29
+ ### What Metric Rating Measures (Code Quality)
30
+ - `iterationVelocity`: Commits/hour (momentum)
31
+ - `reworkRatio`: % fix commits (building vs debugging)
32
+ - `trustPassRate`: % commits that stick (code quality)
33
+ - `debugSpiralDuration`: Time stuck in fix chains
34
+ - `flowEfficiency`: % time productive
35
+
36
+ **Good for:** Measuring actual coding effectiveness, quality outcomes
37
+
38
+ ### Recommendation
39
+
40
+ **Show both** with clear labels. The metric-based rating is the better "grade" because it directly measures outcomes (did code stick? were you building or fixing?). The vibeScore is a supporting indicator.
41
+
42
+ ---
43
+
44
+ ## Approach Selected
45
+
46
+ **Option 3: Show both scores with distinct meanings**
47
+
48
+ - Primary: **Code Health** (metric-based) - the "grade"
49
+ - Secondary: **Pattern Score** (vibeScore) - the "trend indicator"
50
+
51
+ **Rationale:**
52
+ - Metric rating directly measures what matters (code quality, productivity)
53
+ - vibeScore catches patterns the metrics might miss
54
+ - Users get complete picture without confusion
55
+
56
+ ---
57
+
58
+ ## Files to Modify
59
+
60
+ ### 1. `src/commands/analyze.ts:37-42`
61
+
62
+ **Purpose:** Revert to using metric-based rating for session recording (the quality grade)
63
+
64
+ **Before:**
65
+ ```typescript
66
+ /**
67
+ * Derive rating from vibeScore percentage to ensure badge matches displayed score
68
+ */
69
+ function vibeScoreToRating(scorePercent: number): OverallRating {
70
+ if (scorePercent >= 85) return 'ELITE';
71
+ if (scorePercent >= 70) return 'HIGH';
72
+ if (scorePercent >= 50) return 'MEDIUM';
73
+ return 'LOW';
74
+ }
75
+ ```
76
+
77
+ **After:**
78
+ ```typescript
79
+ // REMOVED - using metric-based rating as primary quality indicator
80
+ // vibeScore is secondary pattern indicator
81
+ ```
82
+
83
+ **Also revert lines 329-333:**
84
+
85
+ **Before:**
86
+ ```typescript
87
+ // Use score-based rating so badge matches displayed percentage
88
+ const scoreBasedRating = vibeScoreToRating(vibeScorePercent);
89
+ const gamificationResult = recordGamificationSession(
90
+ vibeScorePercent,
91
+ scoreBasedRating,
92
+ ```
93
+
94
+ **After:**
95
+ ```typescript
96
+ // Use metric-based rating as primary quality indicator
97
+ const gamificationResult = recordGamificationSession(
98
+ vibeScorePercent,
99
+ result.overall, // Metric-based rating (quality grade)
100
+ ```
101
+
102
+ **Validation:** `npm run build` passes
103
+
104
+ ---
105
+
106
+ ### 2. `src/insights/index.ts:23-31`
107
+
108
+ **Purpose:** Remove vibeScoreToRating helper (no longer needed in dashboard builder)
109
+
110
+ **Before:**
111
+ ```typescript
112
+ import { Commit, OverallRating } from '../types';
113
+
114
+ /**
115
+ * Derive rating from vibeScore percentage to ensure badge matches displayed score
116
+ */
117
+ function vibeScoreToRating(scorePercent: number): OverallRating {
118
+ if (scorePercent >= 85) return 'ELITE';
119
+ if (scorePercent >= 70) return 'HIGH';
120
+ if (scorePercent >= 50) return 'MEDIUM';
121
+ return 'LOW';
122
+ }
123
+ ```
124
+
125
+ **After:**
126
+ ```typescript
127
+ import { Commit } from '../types';
128
+ ```
129
+
130
+ ---
131
+
132
+ ### 3. `src/insights/index.ts:97-102`
133
+
134
+ **Purpose:** Revert rating distribution to use stored metric-based ratings
135
+
136
+ **Before:**
137
+ ```typescript
138
+ // Rating distribution (recalculate from vibeScore to ensure consistency)
139
+ const ratingDistribution: Record<string, number> = { ELITE: 0, HIGH: 0, MEDIUM: 0, LOW: 0 };
140
+ for (const s of sessions) {
141
+ const rating = vibeScoreToRating(s.vibeScore);
142
+ ratingDistribution[rating] = (ratingDistribution[rating] || 0) + 1;
143
+ }
144
+ ```
145
+
146
+ **After:**
147
+ ```typescript
148
+ // Rating distribution from metric-based quality grades
149
+ const ratingDistribution: Record<string, number> = { ELITE: 0, HIGH: 0, MEDIUM: 0, LOW: 0 };
150
+ for (const s of sessions) {
151
+ ratingDistribution[s.overall] = (ratingDistribution[s.overall] || 0) + 1;
152
+ }
153
+ ```
154
+
155
+ ---
156
+
157
+ ### 4. `src/insights/index.ts:129-135`
158
+
159
+ **Purpose:** Revert scoreTrend to use stored metric-based ratings
160
+
161
+ **Before:**
162
+ ```typescript
163
+ // Score trend (last 30 sessions, oldest first for chart)
164
+ // Recalculate rating from vibeScore to ensure badge matches score
165
+ const scoreTrend = sessions.slice(-30).map(s => ({
166
+ date: s.date,
167
+ score: s.vibeScore,
168
+ rating: vibeScoreToRating(s.vibeScore),
169
+ }));
170
+ ```
171
+
172
+ **After:**
173
+ ```typescript
174
+ // Score trend (last 30 sessions, oldest first for chart)
175
+ const scoreTrend = sessions.slice(-30).map(s => ({
176
+ date: s.date,
177
+ score: s.vibeScore,
178
+ rating: s.overall, // Metric-based quality grade
179
+ }));
180
+ ```
181
+
182
+ ---
183
+
184
+ ### 5. `src/insights/index.ts:188-192`
185
+
186
+ **Purpose:** Revert current stats to use stored metric-based rating
187
+
188
+ **Before:**
189
+ ```typescript
190
+ stats: {
191
+ current: {
192
+ vibeScore: latestSession?.vibeScore || 0,
193
+ rating: latestSession ? vibeScoreToRating(latestSession.vibeScore) : 'N/A',
194
+ },
195
+ ```
196
+
197
+ **After:**
198
+ ```typescript
199
+ stats: {
200
+ current: {
201
+ vibeScore: latestSession?.vibeScore || 0,
202
+ rating: latestSession?.overall || 'N/A', // Metric-based quality grade
203
+ },
204
+ ```
205
+
206
+ ---
207
+
208
+ ### 6. `src/insights/index.ts:216-224`
209
+
210
+ **Purpose:** Revert sessions mapping to use stored metric-based ratings
211
+
212
+ **Before:**
213
+ ```typescript
214
+ sessions: sessions.slice(-50).reverse().map(s => ({
215
+ date: s.date,
216
+ vibeScore: s.vibeScore,
217
+ rating: vibeScoreToRating(s.vibeScore), // Recalculate from score
218
+ commits: s.commits,
219
+ spirals: s.spirals,
220
+ xpEarned: s.xpEarned,
221
+ metrics: s.metrics || null, // Include detailed metrics if available
222
+ })),
223
+ ```
224
+
225
+ **After:**
226
+ ```typescript
227
+ sessions: sessions.slice(-50).reverse().map(s => ({
228
+ date: s.date,
229
+ vibeScore: s.vibeScore,
230
+ rating: s.overall, // Metric-based quality grade
231
+ commits: s.commits,
232
+ spirals: s.spirals,
233
+ xpEarned: s.xpEarned,
234
+ metrics: s.metrics || null, // Include detailed metrics if available
235
+ })),
236
+ ```
237
+
238
+ ---
239
+
240
+ ### 7. `dashboard/index.html:92-100`
241
+
242
+ **Purpose:** Clarify what each score means in the UI
243
+
244
+ **Before:**
245
+ ```html
246
+ <div class="stat-card highlight">
247
+ <div class="stat-icon">🎯</div>
248
+ <div class="stat-content">
249
+ <span class="stat-value" id="currentScore">--</span>
250
+ <span class="stat-label">Current Vibe Score</span>
251
+ <span class="stat-hint" title="Code pattern health (0-100%)">Pattern Health</span>
252
+ </div>
253
+ </div>
254
+ ```
255
+
256
+ **After:**
257
+ ```html
258
+ <div class="stat-card highlight">
259
+ <div class="stat-icon">🎯</div>
260
+ <div class="stat-content">
261
+ <span class="stat-value" id="currentScore">--</span>
262
+ <span class="stat-label">Pattern Score</span>
263
+ <span class="stat-hint" title="Workflow pattern health (file churn, spirals, stability)">Workflow Patterns</span>
264
+ </div>
265
+ </div>
266
+ ```
267
+
268
+ ---
269
+
270
+ ### 8. `dashboard/index.html` (after line 121, before stats-grid closing div)
271
+
272
+ **Purpose:** Add Code Health rating card to show metric-based grade
273
+
274
+ **Insert:**
275
+ ```html
276
+ <div class="stat-card">
277
+ <div class="stat-icon">⚡</div>
278
+ <div class="stat-content">
279
+ <span class="stat-value rating-badge" id="codeHealthRating">--</span>
280
+ <span class="stat-label">Code Health</span>
281
+ <span class="stat-hint" title="Quality grade from velocity, trust, rework, flow metrics">Quality Grade</span>
282
+ </div>
283
+ </div>
284
+ ```
285
+
286
+ ---
287
+
288
+ ### 9. `dashboard/app.js` - updateStats function
289
+
290
+ **Purpose:** Populate the new Code Health rating display
291
+
292
+ **Find the updateStats function and add after currentScore update:**
293
+
294
+ ```javascript
295
+ // Code Health rating (metric-based quality grade)
296
+ const codeHealthEl = document.getElementById('codeHealthRating');
297
+ if (codeHealthEl && stats.current.rating) {
298
+ codeHealthEl.textContent = stats.current.rating;
299
+ codeHealthEl.className = 'stat-value rating-badge rating-' + stats.current.rating.toLowerCase();
300
+ }
301
+ ```
302
+
303
+ ---
304
+
305
+ ### 10. `dashboard/styles.css`
306
+
307
+ **Purpose:** Style the rating badge in stats card
308
+
309
+ **Add:**
310
+ ```css
311
+ /* Rating badge in stats card */
312
+ .stat-value.rating-badge {
313
+ font-size: 1.25rem;
314
+ font-weight: 700;
315
+ padding: 4px 12px;
316
+ border-radius: 6px;
317
+ }
318
+
319
+ .rating-badge.rating-elite {
320
+ background: linear-gradient(135deg, #fbbf24, #f59e0b);
321
+ color: #1a1a2e;
322
+ }
323
+
324
+ .rating-badge.rating-high {
325
+ background: linear-gradient(135deg, #34d399, #10b981);
326
+ color: #1a1a2e;
327
+ }
328
+
329
+ .rating-badge.rating-medium {
330
+ background: linear-gradient(135deg, #60a5fa, #3b82f6);
331
+ color: white;
332
+ }
333
+
334
+ .rating-badge.rating-low {
335
+ background: linear-gradient(135deg, #f87171, #ef4444);
336
+ color: white;
337
+ }
338
+ ```
339
+
340
+ ---
341
+
342
+ ## Implementation Order
343
+
344
+ **CRITICAL: Sequence matters. Do not reorder.**
345
+
346
+ | Step | Action | Validation | Rollback |
347
+ |------|--------|------------|----------|
348
+ | 1 | Revert analyze.ts changes | `npm run build` | git checkout |
349
+ | 2 | Revert insights/index.ts changes | `npm run build` | git checkout |
350
+ | 3 | Update index.html stat cards | Visual check | git checkout |
351
+ | 4 | Update app.js for new element | Browser console | git checkout |
352
+ | 5 | Add CSS styles | Visual check | git checkout |
353
+ | 6 | Regenerate dashboard | `node dist/cli.js dashboard` | N/A |
354
+ | 7 | Full verification | Visual inspection | Revert all |
355
+
356
+ ---
357
+
358
+ ## Validation Strategy
359
+
360
+ ### Build Validation
361
+ ```bash
362
+ npm run build
363
+ # Expected: No errors
364
+ ```
365
+
366
+ ### Dashboard Generation
367
+ ```bash
368
+ node dist/cli.js dashboard
369
+ # Expected: Opens dashboard with both scores visible
370
+ ```
371
+
372
+ ### Visual Validation
373
+ - Pattern Score shows percentage (e.g., "79%")
374
+ - Code Health shows rating badge (e.g., "ELITE" or "HIGH")
375
+ - Session list shows metric-based ratings
376
+ - Ratings now reflect actual code quality metrics
377
+
378
+ ---
379
+
380
+ ## Rollback Procedure
381
+
382
+ **Time to rollback:** 2 minutes
383
+
384
+ ```bash
385
+ # Full rollback
386
+ git checkout -- src/commands/analyze.ts src/insights/index.ts dashboard/
387
+ npm run build
388
+ ```
389
+
390
+ ---
391
+
392
+ ## Risk Assessment
393
+
394
+ ### Low Risk
395
+ - **What:** UI changes only, no data loss
396
+ - **Mitigation:** Simple git revert available
397
+ - **Detection:** Visual inspection
398
+ - **Recovery:** git checkout
399
+
400
+ ---
401
+
402
+ ## Approval Checklist
403
+
404
+ **Human must verify before /implement:**
405
+
406
+ - [ ] Agree that metric-based rating is better "quality grade"
407
+ - [ ] Agree that vibeScore is useful as "pattern indicator"
408
+ - [ ] Approve showing both with distinct labels
409
+ - [ ] Approve reverting quick fix changes
410
+
411
+ ---
412
+
413
+ ## Alternative: Simpler Approach
414
+
415
+ If you prefer NOT to show both, we could instead:
416
+
417
+ **Option A: Just add labels to current approach**
418
+ - Keep vibeScore-based rating
419
+ - Relabel as "Pattern Grade"
420
+ - Minimal changes
421
+
422
+ **Option B: Just use metric rating everywhere**
423
+ - Revert all vibeScore-to-rating changes
424
+ - Accept that number and badge may differ
425
+ - Add tooltip explaining the difference
426
+
427
+ Let me know which approach you prefer before implementation.