veritas-kanban/scripts/coverage-policy-utils.mjs
Brad Groux 93e946693d
test: establish critical-path coverage ratchets (#1183)
* test: add critical-path coverage ratchets

* fix: harden coverage ratchet enforcement

* fix: fetch coverage comparison history

* fix: close coverage policy downgrade paths

* fix: verify changed critical statements

* fix: ignore non-executable coverage changes

* fix: distinguish mixed type-only coverage edits

* fix: classify coverage changes by runtime output

* fix: enforce runtime-significant whitespace changes

* fix: classify multiline coverage changes as hunks

* fix: group equal-line coverage rewrites
2026-08-23 13:48:41 -05:00

45 lines
1.8 KiB
JavaScript

import path from 'node:path';
const ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
const GITHUB_LOGIN_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/;
const TRACKING_ISSUE_PATTERN = /^#\d+$/;
const GLOB_PATTERN = /[*?[\]{}!]/;
function isValidIsoDate(value) {
if (typeof value !== 'string' || !ISO_DATE_PATTERN.test(value)) return false;
const date = new Date(`${value}T00:00:00.000Z`);
return !Number.isNaN(date.valueOf()) && date.toISOString().slice(0, 10) === value;
}
export function coverageExceptionErrors(exception, label, today) {
const errors = [];
const normalized = path.posix.normalize(exception.path ?? '');
if (
!exception.path ||
normalized !== exception.path ||
normalized.startsWith('../') ||
path.posix.isAbsolute(normalized) ||
GLOB_PATTERN.test(normalized)
) {
errors.push(`${label} exception path must be one exact repository-relative file`);
}
if (typeof exception.reason !== 'string' || exception.reason.trim().length < 20) {
errors.push(`${label} exception reason must contain at least 20 characters`);
}
if (!GITHUB_LOGIN_PATTERN.test(exception.owner ?? '')) {
errors.push(`${label} exception owner must be a GitHub login`);
}
if (!TRACKING_ISSUE_PATTERN.test(exception.trackingIssue ?? '')) {
errors.push(`${label} exception must reference a tracking issue such as #123`);
}
if (!isValidIsoDate(exception.reviewBy)) {
errors.push(`${label} exception reviewBy must be a real YYYY-MM-DD date`);
return errors;
}
const maximum = new Date(`${today}T00:00:00.000Z`);
maximum.setUTCDate(maximum.getUTCDate() + 90);
if (exception.reviewBy < today || exception.reviewBy > maximum.toISOString().slice(0, 10)) {
errors.push(`${label} exception reviewBy must be today or within the next 90 days`);
}
return errors;
}