@boshu2/vibe-check 0.1.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 (143) hide show
  1. package/.dockerignore +46 -0
  2. package/.gitattributes +3 -0
  3. package/.pre-commit-hooks.yaml +11 -0
  4. package/AGENTS.md +40 -0
  5. package/CHANGELOG.md +322 -0
  6. package/CLAUDE.md +342 -0
  7. package/CONTRIBUTING.md +227 -0
  8. package/Dockerfile +26 -0
  9. package/LICENSE +201 -0
  10. package/Makefile +213 -0
  11. package/README.md +165 -0
  12. package/SECURITY.md +182 -0
  13. package/action.yml +270 -0
  14. package/assets/logo-dark.svg +47 -0
  15. package/assets/logo.svg +47 -0
  16. package/bin/vc.js +2 -0
  17. package/bin/vibe-check.js +2 -0
  18. package/claude-progress.json +312 -0
  19. package/claude-progress.txt +572 -0
  20. package/dist/cli.d.ts +3 -0
  21. package/dist/cli.d.ts.map +1 -0
  22. package/dist/cli.js +70 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/commands/analyze-helpers.d.ts +43 -0
  25. package/dist/commands/analyze-helpers.d.ts.map +1 -0
  26. package/dist/commands/analyze-helpers.js +124 -0
  27. package/dist/commands/analyze-helpers.js.map +1 -0
  28. package/dist/commands/analyze.d.ts +21 -0
  29. package/dist/commands/analyze.d.ts.map +1 -0
  30. package/dist/commands/analyze.js +114 -0
  31. package/dist/commands/analyze.js.map +1 -0
  32. package/dist/commands/index.d.ts +2 -0
  33. package/dist/commands/index.d.ts.map +1 -0
  34. package/dist/commands/index.js +2 -0
  35. package/dist/commands/index.js.map +1 -0
  36. package/dist/errors.d.ts +100 -0
  37. package/dist/errors.d.ts.map +1 -0
  38. package/dist/errors.js +208 -0
  39. package/dist/errors.js.map +1 -0
  40. package/dist/git.d.ts +39 -0
  41. package/dist/git.d.ts.map +1 -0
  42. package/dist/git.js +206 -0
  43. package/dist/git.js.map +1 -0
  44. package/dist/inner-loop/context-amnesia.d.ts +20 -0
  45. package/dist/inner-loop/context-amnesia.d.ts.map +1 -0
  46. package/dist/inner-loop/context-amnesia.js +246 -0
  47. package/dist/inner-loop/context-amnesia.js.map +1 -0
  48. package/dist/inner-loop/index.d.ts +39 -0
  49. package/dist/inner-loop/index.d.ts.map +1 -0
  50. package/dist/inner-loop/index.js +181 -0
  51. package/dist/inner-loop/index.js.map +1 -0
  52. package/dist/inner-loop/instruction-drift.d.ts +36 -0
  53. package/dist/inner-loop/instruction-drift.d.ts.map +1 -0
  54. package/dist/inner-loop/instruction-drift.js +270 -0
  55. package/dist/inner-loop/instruction-drift.js.map +1 -0
  56. package/dist/inner-loop/logging-only.d.ts +64 -0
  57. package/dist/inner-loop/logging-only.d.ts.map +1 -0
  58. package/dist/inner-loop/logging-only.js +292 -0
  59. package/dist/inner-loop/logging-only.js.map +1 -0
  60. package/dist/inner-loop/tests-passing-lie.d.ts +34 -0
  61. package/dist/inner-loop/tests-passing-lie.d.ts.map +1 -0
  62. package/dist/inner-loop/tests-passing-lie.js +213 -0
  63. package/dist/inner-loop/tests-passing-lie.js.map +1 -0
  64. package/dist/inner-loop/types.d.ts +125 -0
  65. package/dist/inner-loop/types.d.ts.map +1 -0
  66. package/dist/inner-loop/types.js +27 -0
  67. package/dist/inner-loop/types.js.map +1 -0
  68. package/dist/internal/context/index.d.ts +74 -0
  69. package/dist/internal/context/index.d.ts.map +1 -0
  70. package/dist/internal/context/index.js +151 -0
  71. package/dist/internal/context/index.js.map +1 -0
  72. package/dist/internal/context/types.d.ts +75 -0
  73. package/dist/internal/context/types.d.ts.map +1 -0
  74. package/dist/internal/context/types.js +8 -0
  75. package/dist/internal/context/types.js.map +1 -0
  76. package/dist/internal/output/contract.d.ts +81 -0
  77. package/dist/internal/output/contract.d.ts.map +1 -0
  78. package/dist/internal/output/contract.js +112 -0
  79. package/dist/internal/output/contract.js.map +1 -0
  80. package/dist/internal/output/index.d.ts +7 -0
  81. package/dist/internal/output/index.d.ts.map +1 -0
  82. package/dist/internal/output/index.js +7 -0
  83. package/dist/internal/output/index.js.map +1 -0
  84. package/dist/metrics/flow.d.ts +20 -0
  85. package/dist/metrics/flow.d.ts.map +1 -0
  86. package/dist/metrics/flow.js +85 -0
  87. package/dist/metrics/flow.js.map +1 -0
  88. package/dist/metrics/index.d.ts +4 -0
  89. package/dist/metrics/index.d.ts.map +1 -0
  90. package/dist/metrics/index.js +161 -0
  91. package/dist/metrics/index.js.map +1 -0
  92. package/dist/metrics/rework.d.ts +12 -0
  93. package/dist/metrics/rework.d.ts.map +1 -0
  94. package/dist/metrics/rework.js +51 -0
  95. package/dist/metrics/rework.js.map +1 -0
  96. package/dist/metrics/spirals.d.ts +17 -0
  97. package/dist/metrics/spirals.d.ts.map +1 -0
  98. package/dist/metrics/spirals.js +157 -0
  99. package/dist/metrics/spirals.js.map +1 -0
  100. package/dist/metrics/trust.d.ts +12 -0
  101. package/dist/metrics/trust.d.ts.map +1 -0
  102. package/dist/metrics/trust.js +175 -0
  103. package/dist/metrics/trust.js.map +1 -0
  104. package/dist/metrics/velocity.d.ts +25 -0
  105. package/dist/metrics/velocity.d.ts.map +1 -0
  106. package/dist/metrics/velocity.js +120 -0
  107. package/dist/metrics/velocity.js.map +1 -0
  108. package/dist/output/index.d.ts +10 -0
  109. package/dist/output/index.d.ts.map +1 -0
  110. package/dist/output/index.js +20 -0
  111. package/dist/output/index.js.map +1 -0
  112. package/dist/output/json.d.ts +3 -0
  113. package/dist/output/json.d.ts.map +1 -0
  114. package/dist/output/json.js +48 -0
  115. package/dist/output/json.js.map +1 -0
  116. package/dist/output/markdown.d.ts +3 -0
  117. package/dist/output/markdown.d.ts.map +1 -0
  118. package/dist/output/markdown.js +84 -0
  119. package/dist/output/markdown.js.map +1 -0
  120. package/dist/output/terminal.d.ts +10 -0
  121. package/dist/output/terminal.d.ts.map +1 -0
  122. package/dist/output/terminal.js +153 -0
  123. package/dist/output/terminal.js.map +1 -0
  124. package/dist/types.d.ts +75 -0
  125. package/dist/types.d.ts.map +1 -0
  126. package/dist/types.js +5 -0
  127. package/dist/types.js.map +1 -0
  128. package/docs/ARCHITECTURE.md +450 -0
  129. package/docs/DEPLOYMENT.md +394 -0
  130. package/docs/METRICS-EXPLAINED.md +394 -0
  131. package/docs/REFERENCE.md +230 -0
  132. package/docs/images/dashboard.png +0 -0
  133. package/drivers/README.md +327 -0
  134. package/drivers/go.sh +131 -0
  135. package/drivers/java.sh +137 -0
  136. package/drivers/javascript.sh +134 -0
  137. package/drivers/php.sh +132 -0
  138. package/drivers/python.sh +90 -0
  139. package/drivers/rust.sh +132 -0
  140. package/feature-list.json +273 -0
  141. package/hooks/pre-push +107 -0
  142. package/package.json +47 -0
  143. package/vitest.config.ts +25 -0
@@ -0,0 +1,450 @@
1
+ # vibe-check Architecture
2
+
3
+ **Technical guide to the vibe-check codebase**
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Overview](#overview)
10
+ 2. [System Architecture](#system-architecture)
11
+ 3. [Module Boundaries](#module-boundaries)
12
+ 4. [Data Flow](#data-flow)
13
+ 5. [Key Design Decisions](#key-design-decisions)
14
+ 6. [Directory Structure](#directory-structure)
15
+ 7. [Error Handling](#error-handling-architecture)
16
+ 8. [Core Modules](#key-modules)
17
+ 9. [Testing Strategy](#testing-strategy)
18
+ 10. [Design Principles](#design-principles)
19
+
20
+ ---
21
+
22
+ ## Overview
23
+
24
+ vibe-check is a TypeScript CLI tool that analyzes git history to measure AI-assisted development effectiveness. It uses **semantic-free signals** from commit patterns to compute metrics without reading code content.
25
+
26
+ ### Core Philosophy
27
+
28
+ - **Privacy-First**: Never reads actual source code, only commit metadata
29
+ - **Git-Native**: All data derived from git history (commits, timestamps, file lists)
30
+ - **Semantic-Free**: Metrics based on patterns, not code semantics
31
+
32
+ ### Technology Stack
33
+
34
+ | Component | Technology | Purpose |
35
+ |-----------|------------|---------|
36
+ | Runtime | Node.js 20+ | ES Modules, native fetch |
37
+ | Language | TypeScript 5.x | Type safety, maintainability |
38
+ | CLI Framework | Commander.js | Command parsing, options |
39
+ | Git Integration | simple-git | Git log, diff-tree operations |
40
+ | Output | chalk | Terminal formatting |
41
+ | Testing | Vitest | Unit and integration tests |
42
+
43
+ ---
44
+
45
+ ## System Architecture
46
+
47
+ ```
48
+ +---------------------------------------------------------------------+
49
+ | CLI Layer |
50
+ | cli.ts -> Commander.js -> Global context -> User I/O |
51
+ | [Entry point, argument parsing, global hooks, output routing] |
52
+ +---------------------------------------------------------------------+
53
+ | Core Layer |
54
+ | +------------+ +------------+ +------------+ |
55
+ | | Metrics | | Inner- | | Errors | |
56
+ | | Engine | | Loop | | Hierarchy | |
57
+ | | (metrics/) | |(inner-loop)| | (errors.ts)| |
58
+ | +------------+ +------------+ +------------+ |
59
+ +---------------------------------------------------------------------+
60
+ | Output Layer |
61
+ | Terminal (chalk) | JSON | Markdown |
62
+ | [output/ - format routing, terminal colors, structured output] |
63
+ +---------------------------------------------------------------------+
64
+ | Data Layer |
65
+ | +-------------+ |
66
+ | | Git Access | |
67
+ | | (git.ts) | |
68
+ | | simple-git | |
69
+ | +-------------+ |
70
+ +---------------------------------------------------------------------+
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Module Boundaries
76
+
77
+ ### Dependency Rules
78
+
79
+ Modules follow a strict layered architecture with downward-only dependencies:
80
+
81
+ ```
82
+ CLI Layer
83
+ | uses
84
+ Core Layer (Metrics + Detection)
85
+ | uses
86
+ Output Layer
87
+ | uses
88
+ Data Layer
89
+ ```
90
+
91
+ **Key Constraints:**
92
+ - Core modules don't know about CLI/output formatting
93
+ - Data layer has no dependencies on upper layers
94
+ - Detection modules are stateless, receive data as parameters
95
+
96
+ ### Module Ownership Matrix
97
+
98
+ | Module | Owner | Boundary | External API |
99
+ |--------|-------|----------|--------------|
100
+ | `cli.ts` | CLI | Entry point | `program.parse()` |
101
+ | `commands/` | Commands | User features | `runAnalyze()` |
102
+ | `metrics/` | Core | Calculations | `analyzeCommits()` |
103
+ | `inner-loop/` | Detection | Failure patterns | `analyzeInnerLoop()` |
104
+ | `output/` | Presentation | Formatting | `formatOutput()` |
105
+
106
+ ### Interface Contracts
107
+
108
+ Each module exposes a clean interface through its `index.ts`:
109
+
110
+ ```typescript
111
+ // metrics/index.ts - Single entry point
112
+ export function analyzeCommits(commits: Commit[]): VibeCheckResult;
113
+
114
+ // inner-loop/index.ts - Aggregated detection
115
+ export function analyzeInnerLoop(
116
+ commits: Commit[],
117
+ config?: InnerLoopConfig
118
+ ): InnerLoopAnalysis;
119
+ ```
120
+
121
+ ---
122
+
123
+ ## Data Flow
124
+
125
+ ### Primary Analysis Pipeline
126
+
127
+ ```
128
+ +------------+ +------------+ +------------+
129
+ | Git History|--->|Parse Commits|--->| Commit[] |
130
+ | (simple-git)| | (git.ts) | | |
131
+ +------------+ +------------+ +-----+------+
132
+ |
133
+ +-----------------------+-----------------------+
134
+ | v |
135
+ | +------------+ +------------+ +----------+ |
136
+ | | Velocity | | Rework | | Trust | |
137
+ | | Metric | | Metric | | Metric | |
138
+ | +-----+------+ +-----+------+ +----+-----+ |
139
+ | | | | |
140
+ | +-------+-------+------+-------+ |
141
+ | | | |
142
+ | v v |
143
+ | +------------+ +------------+ |
144
+ | | Flow | | Spirals | |
145
+ | | Metric | | Detection | |
146
+ | +-----+------+ +-----+------+ |
147
+ | | | |
148
+ | +-------+-------+ |
149
+ | v |
150
+ | +------------+ |
151
+ | |MetricResult| |
152
+ | | (5 core) | |
153
+ | +-----+------+ |
154
+ | metrics/ | |
155
+ +---------------------+-------------------------+
156
+ |
157
+ +---------------------+---------------------+
158
+ | v |
159
+ | +----------+ +----------+ +--------+ |
160
+ | | Terminal | | JSON | |Markdown| |
161
+ | | Output | | Output | | Output | |
162
+ | +----------+ +----------+ +--------+ |
163
+ | output/ |
164
+ +-------------------------------------------+
165
+ ```
166
+
167
+ ### Detection Pipeline (Inner-Loop)
168
+
169
+ ```
170
+ Commit[]
171
+ |
172
+ v
173
+ +------------------+
174
+ | Inner-Loop |
175
+ | Detection |
176
+ +------------------+
177
+ | - Tests Lie |
178
+ | - Amnesia |
179
+ | - Drift |
180
+ | - Debug Loop |
181
+ +--------+---------+
182
+ |
183
+ v
184
+ +------------------+
185
+ | Recommendations |
186
+ +------------------+
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Key Design Decisions
192
+
193
+ ### 1. Semantic-Free Analysis
194
+
195
+ **Decision:** Never parse or read source code content.
196
+
197
+ **Rationale:**
198
+ - Privacy: Users trust tool with git metadata, not code
199
+ - Performance: No AST parsing, instant analysis
200
+ - Language-agnostic: Works for any language
201
+ - Focus: Patterns, not implementation details
202
+
203
+ **Trade-off:** Cannot detect code quality issues, only behavioral patterns.
204
+
205
+ ### 2. Layered Error Handling
206
+
207
+ **Decision:** Custom error hierarchy with semantic exit codes.
208
+
209
+ **Rationale:**
210
+ - CI/CD integration: Exit codes enable scripted responses
211
+ - Debug-friendly: Errors carry full context
212
+ - User-friendly: Clear, actionable error messages
213
+ - Testable: Commands return exit codes, not `process.exit()`
214
+
215
+ ```typescript
216
+ // Commands return ExitCode, CLI layer handles exit
217
+ export async function runAnalyze(options): Promise<ExitCode> {
218
+ try { ... }
219
+ catch (error) {
220
+ if (isVibeCheckError(error)) {
221
+ return error.code; // Semantic exit code
222
+ }
223
+ return ExitCode.GENERAL_ERROR;
224
+ }
225
+ }
226
+ ```
227
+
228
+ ### 3. Global Context Singleton
229
+
230
+ **Decision:** Single context object for CLI state.
231
+
232
+ **Rationale:**
233
+ - Consistency: All modules see same repo path, output mode
234
+ - Simplicity: No context threading through call chains
235
+ - Hook-friendly: Set once in preAction, available everywhere
236
+
237
+ ```typescript
238
+ // Set in CLI preAction hook
239
+ setContext(createContext({ repo: opts.repo, outputMode: 'json' }));
240
+
241
+ // Access anywhere
242
+ const { repo, outputMode } = getContext();
243
+ ```
244
+
245
+ ### 4. Single Command Design
246
+
247
+ **Decision:** One main command (`vc`) with options instead of subcommands.
248
+
249
+ **Rationale:**
250
+ - Simplicity: Most common use case is quick analysis
251
+ - Fast: No subcommand parsing overhead
252
+ - Discoverable: `--help` shows all options at once
253
+
254
+ ---
255
+
256
+ ## Directory Structure
257
+
258
+ ```
259
+ src/
260
+ +-- cli.ts # Entry point, Commander.js setup, global hooks
261
+ +-- git.ts # Git operations (simple-git wrapper)
262
+ +-- types.ts # Core TypeScript interfaces
263
+ +-- errors.ts # Custom error hierarchy with semantic exit codes
264
+ |
265
+ +-- internal/ # Shared CLI utilities
266
+ | +-- context/ # Global context (repo path, output mode)
267
+ | | +-- index.ts # Context creation and management
268
+ | | +-- types.ts # Context type definitions
269
+ | +-- output/ # Output formatting utilities
270
+ | +-- index.ts # Output helpers
271
+ | +-- contract.ts # Agent output contract
272
+ |
273
+ +-- commands/ # CLI command implementations
274
+ | +-- index.ts # Command exports
275
+ | +-- analyze.ts # Main analysis command
276
+ | +-- analyze-helpers.ts # Data loading, metrics computation, output formatting
277
+ |
278
+ +-- metrics/ # Metric calculations
279
+ | +-- index.ts # Orchestrates all metrics
280
+ | +-- velocity.ts # Iteration velocity
281
+ | +-- rework.ts # Rework ratio
282
+ | +-- trust.ts # Trust pass rate
283
+ | +-- spirals.ts # Debug spiral detection
284
+ | +-- flow.ts # Flow efficiency
285
+ |
286
+ +-- inner-loop/ # Inner Loop Failure Detection
287
+ | +-- index.ts # Aggregator for all detectors
288
+ | +-- types.ts # Types and configuration
289
+ | +-- tests-passing-lie.ts # "Tests Passing" Lie detector
290
+ | +-- context-amnesia.ts # Context Amnesia detector
291
+ | +-- instruction-drift.ts # Instruction Drift detector
292
+ | +-- logging-only.ts # Debug Loop Spiral detector
293
+ |
294
+ +-- output/ # Output formatters
295
+ +-- index.ts # Format router
296
+ +-- terminal.ts # Colored terminal output
297
+ +-- json.ts # JSON output
298
+ +-- markdown.ts # Markdown output
299
+ ```
300
+
301
+ ---
302
+
303
+ ## Error Handling Architecture
304
+
305
+ ### Error Hierarchy
306
+
307
+ ```typescript
308
+ VibeCheckError (base)
309
+ +-- GitError (exit code 2)
310
+ | +-- notARepo(path)
311
+ | +-- logFailed(reason)
312
+ | +-- commitNotFound(hash)
313
+ +-- ValidationError (exit code 3)
314
+ | +-- invalidFormat(format, validFormats)
315
+ | +-- invalidDateRange(since, until)
316
+ | +-- missingRequired(option)
317
+ +-- AnalysisError (exit code 6)
318
+ +-- noCommits(since, until)
319
+ +-- insufficientData(required, actual)
320
+ ```
321
+
322
+ ### Exit Codes
323
+
324
+ | Code | Meaning |
325
+ |------|---------|
326
+ | 0 | Success |
327
+ | 1 | General error / LOW rating |
328
+ | 2 | Git error |
329
+ | 3 | Validation error |
330
+ | 6 | Analysis error |
331
+
332
+ ---
333
+
334
+ ## Key Modules
335
+
336
+ ### Internal Context (`internal/context/`)
337
+
338
+ Global context for CLI operations:
339
+
340
+ ```typescript
341
+ interface CLIContext {
342
+ repo: string; // Repository path
343
+ outputMode: 'terminal' | 'json';
344
+ verbose: boolean;
345
+ quiet: boolean;
346
+ debug?: boolean;
347
+ timeout: number;
348
+ maxCommits?: number;
349
+ version: string;
350
+ }
351
+ ```
352
+
353
+ Set once at command start, accessed throughout:
354
+
355
+ ```typescript
356
+ import { getContext } from './internal/context/index.js';
357
+ const ctx = getContext();
358
+ ```
359
+
360
+ ---
361
+
362
+ ## Inner Loop Failure Detection
363
+
364
+ Detects the 4 "Inner Loop Disasters" from vibe coding:
365
+
366
+ | Pattern | Detects | Detection Method |
367
+ |---------|---------|------------------|
368
+ | **Tests Passing Lie** | AI claims success but fails | Commits with "fix/done/working" followed by immediate fixes |
369
+ | **Context Amnesia** | AI forgets instructions | Reverts, reimplementations, repeated similar fixes |
370
+ | **Instruction Drift** | AI "improves" unrequested | Unrequested refactors, scope explosion |
371
+ | **Debug Loop Spiral** | AI adds logging only | Consecutive console.log commits without fixes |
372
+
373
+ ### Detection Architecture
374
+
375
+ ```
376
+ src/inner-loop/
377
+ +-- index.ts # Aggregates all detectors
378
+ +-- types.ts # Types, thresholds, config
379
+ +-- tests-passing-lie.ts # Lie detection
380
+ +-- context-amnesia.ts # Memory loss detection
381
+ +-- instruction-drift.ts # Scope creep detection
382
+ +-- logging-only.ts # Debug spam detection
383
+ ```
384
+
385
+ ---
386
+
387
+ ## Metric Calculations
388
+
389
+ ### Core Metrics (5)
390
+
391
+ | Metric | Formula | Elite Threshold |
392
+ |--------|---------|-----------------|
393
+ | Iteration Velocity | `commits / activeHours` | >5/hr |
394
+ | Rework Ratio | `fixCommits / totalCommits` | <30% |
395
+ | Trust Pass Rate | `1 - immediateFixRate` | >95% |
396
+ | Debug Spiral Duration | `avgSpiralMinutes` | <15m |
397
+ | Flow Efficiency | `buildTime / totalTime` | >90% |
398
+
399
+ ---
400
+
401
+ ## Testing Strategy
402
+
403
+ ### Test Organization
404
+
405
+ ```
406
+ tests/
407
+ +-- inner-loop.test.ts # Inner loop detection
408
+ +-- cli.integration.test.ts # End-to-end CLI tests
409
+ +-- ...
410
+ ```
411
+
412
+ ---
413
+
414
+ ## Design Principles
415
+
416
+ 1. **Semantic-Free** - Analyze patterns, not code content
417
+ 2. **Privacy-First** - Never read actual source code
418
+ 3. **Git-Native** - All data from git history
419
+ 4. **Errors as Values** - Custom error hierarchy with context
420
+ 5. **Zero External Dependencies** - Works offline
421
+ 6. **Testable Architecture** - Commands return results, CLI wrapper handles exit
422
+
423
+ ---
424
+
425
+ ## CLI Options Reference
426
+
427
+ ```bash
428
+ vc [options]
429
+
430
+ Options:
431
+ --json Output JSON
432
+ --timeout <seconds> Git timeout in seconds (default: 120)
433
+ --max-commits <number> Max commits to analyze
434
+ --since <date> Start date (e.g., "1 week ago")
435
+ --until <date> End date (default: now)
436
+ -f, --format <type> Output format: terminal, json, markdown
437
+ -r, --repo <path> Repository path (default: cwd)
438
+ -v, --verbose Verbose output
439
+ -q, --quiet Quiet output
440
+ --debug Debug logging
441
+ --score Include VibeScore metrics
442
+ -o, --output <file> Write JSON to file
443
+ -s, --simple Simple output
444
+ --scope <scope> Filter by scope
445
+ ```
446
+
447
+ ---
448
+
449
+ **Version:** 0.1.0
450
+ **Last Updated:** 2025-12-30