Scoring Methodology
Ratchet evaluates your codebase across 6 orthogonal dimensions, each scored 0โ100. The composite score is a weighted average โ giving you a single ratchet number that can only go up.
# All inputs normalized 0โ100. Score is always an integer.
Ratchet instruments your test runner (Jest, Vitest, pytest, Go test) and collects Istanbul/coverage.py output. Branch coverage is weighted 1.4ร over line coverage to reward tests that exercise conditional logic.
export function divide(a, b) { return a / b; // division by zero? // NaN? Infinity? nobody knows. }
export function divide(a, b) { if (b === 0) throw new Error('div/0'); return a / b; } // divide.test.ts it('throws on zero', () => expect(() => divide(1,0)).toThrow()); it('returns quotient', () => expect(divide(10,2)).toBe(5));
Ratchet uses the McCabe cyclomatic complexity metric. A score of 1 = no branches. Each if, &&, ||, loop, or catch adds 1. Functions above 10 receive zero complexity points and trigger a quick-fix suggestion to extract sub-functions.
function processOrder(order) { if (order.type === 'digital') { if (order.paid) { if (order.email) { try { sendEmail(order.email); if (order.coupon) { applyCoupon(order); } } catch(e) { /* ... */ } } } } else if (order.type === 'physical') { // ... 40 more lines } }
function fulfillDigital(order) { if (!order.paid || !order.email) return; try { sendEmail(order.email); if (order.coupon) applyCoupon(order); } catch(e) { log(e); } } function processOrder(order) { const handlers = { digital: fulfillDigital, physical: fulfillPhysical, }; handlers[order.type]?.(order); }
Only exported symbols (functions, classes, types) count. Internal helpers are excluded to avoid documentation noise. Ratchet checks for a summary sentence, parameter descriptions, and a return type annotation.
export function formatCurrency( amount, currency, locale ) { return new Intl.NumberFormat(locale, { style: 'currency', currency, }).format(amount); }
/** * Format a number as a locale-aware * currency string. * @param amount - Numeric value * @param currency - ISO 4217 code * @param locale - BCP 47 locale tag * @returns Formatted string, e.g. "$1,234.56" */ export function formatCurrency( amount: number, currency: string, locale: string ): string { /* ... */ }
Ratchet penalizes empty catch blocks, swallowed errors, and unhandled promise rejections. It rewards typed error discrimination (using instanceof or error codes), explicit re-throws, and boundary-level fallbacks.
async function fetchUser(id) { try { const res = await api.get(`/users/${id}`); return res.data; } catch (e) { // TODO: handle this later return null; } }
async function fetchUser(id: string) : Promise<User> { try { const res = await api.get(`/users/${id}`); return parseUser(res.data); } catch (e) { if (e instanceof NotFoundError) return null; logger.error('fetchUser failed', { id, e }); throw e; } }
For TypeScript projects, Ratchet counts any escapes, missing return types, and unannotated function parameters. For Python, it checks mypy --strict compliance. Dynamically-typed projects (vanilla JS) are evaluated on JSDoc type annotations instead.
function transform(data: any): any { const result: any = {}; for (const key in data) { result[key] = data[key]; } return result; }
function transform<T extends Record <string, unknown>>(data: T): T { const result = {} as T; for (const key in data) { result[key] = data[key]; } return result; }
Ratchet integrates with Semgrep (open rules set) to detect SQL injection, XSS, hardcoded credentials, unsafe deserialization, and path traversal. Each high-severity finding deducts 3 pts; medium findings deduct 1 pt. Security score floors at 0.
async function getUser(username) { const sql = `SELECT * FROM users WHERE username='${username}'`; return db.query(sql); // username = "' OR '1'='1" }
async function getUser( username: string ): Promise<User | null> { return db.query( 'SELECT * FROM users WHERE username=?', [username] ); }
Grade Scale
Your composite score maps to a letter grade displayed in ratchet scan output and CI badges.
| Grade | Score Range | Description |
|---|---|---|
| S | 90 โ 100 | Exceptional. Ship it with confidence. |
| A | 80 โ 89 | Production-ready. Minor gaps only. |
| B | 65 โ 79 | Good baseline. Worth a quick-fix pass. |
| C | 50 โ 64 | Needs attention. Run ratchet fix. |
| D | 35 โ 49 | Significant debt. Prioritize this sprint. |
| F | 0 โ 34 | Critical issues. Block merges until resolved. |