app/lib/health/verdicts.mjs
401 lines and 37 functions in DrDustinEdwards/dustinedwards-info, at commit 1590ba4 on 2026-10-24. This file on GitHub.
Functions
| Function | Lines | Complexity | Covered | CRAP | Mutation |
|---|---|---|---|---|---|
| setDrift | 10 to 17 | 1 | 17% | OkCRAP 1.6 | Critical0% |
| <anonymous:14> | 14 to 14 | 1 | 0% | OkCRAP 2 | Critical0% |
| <anonymous:15> | 15 to 15 | 1 | 0% | OkCRAP 2 | Critical0% |
| askDriftVerdict | 25 to 41 | 2 | 100% | OkCRAP 2 | Ok100% |
| mediaDriftVerdict | 50 to 67 | 2 | 100% | OkCRAP 2 | Ok100% |
| mediaBackupDriftVerdict | 76 to 108 | 6 | 100% | WatchCRAP 6 | Ok81.8% |
| contentDriftCompare | 126 to 147 | 1 | 100% | OkCRAP 1 | Watch62.5% |
| <anonymous:127> | 127 to 127 | 1 | 100% | OkCRAP 1 | Ok100% |
| <anonymous:128> | 128 to 128 | 1 | 100% | OkCRAP 1 | Ok100% |
| <anonymous:131> | 131 to 134 | 2 | 100% | OkCRAP 2 | Ok100% |
| <anonymous:135> | 135 to 135 | 1 | 100% | OkCRAP 1 | Ok100% |
| <anonymous:138> | 138 to 138 | 1 | 100% | OkCRAP 1 | Ok100% |
| <anonymous:139> | 139 to 139 | 1 | 100% | OkCRAP 1 | Ok100% |
| <anonymous:142> | 142 to 142 | 1 | 100% | OkCRAP 1 | Ok100% |
| <anonymous:143> | 143 to 143 | 1 | 100% | OkCRAP 1 | Ok100% |
| contentDriftVerdict | 156 to 158 | 1 | 100% | OkCRAP 1 | Ok80% |
| procedureDriftVerdict | 168 to 174 | 1 | 100% | OkCRAP 1 | Ok100% |
| dictionaryDriftVerdict | 183 to 185 | 1 | 100% | OkCRAP 1 | Ok100% |
| pageDriftVerdict | 194 to 196 | 1 | 100% | OkCRAP 1 | Ok100% |
| cvDriftVerdict | 205 to 207 | 1 | 100% | OkCRAP 1 | Ok100% |
| cvPdfDriftVerdict | 217 to 232 | 4 | 100% | OkCRAP 4 | Ok95.5% |
| publicationDriftVerdict | 241 to 243 | 1 | 100% | OkCRAP 1 | Ok100% |
| rosterDriftVerdict | 252 to 254 | 1 | 100% | OkCRAP 1 | Ok100% |
| phageDriftVerdict | 263 to 265 | 1 | 100% | OkCRAP 1 | Ok100% |
| registryDriftVerdict | 274 to 276 | 1 | 100% | OkCRAP 1 | Watch60% |
| llmsDriftVerdict | 285 to 287 | 1 | 100% | OkCRAP 1 | Ok80% |
| sourceDriftVerdict | 295 to 312 | 2 | 100% | OkCRAP 2 | Ok100% |
| ftsEqualityVerdict | 321 to 371 | 9 | 100% | WatchCRAP 9 | Watch66.7% |
| <anonymous:324> | 324 to 324 | 2 | 100% | OkCRAP 2 | Ok88.9% |
| withTimeout | 385 to 410 | 1 | 100% | OkCRAP 1 | Ok100% |
| <anonymous:386> | 386 to 409 | 1 | 100% | OkCRAP 1 | Ok100% |
| <anonymous:388> | 388 to 392 | 1 | 100% | OkCRAP 1 | Ok100% |
| <anonymous:397> | 397 to 400 | 1 | 100% | OkCRAP 1 | Watch66.7% |
| <anonymous:401> | 401 to 407 | 1 | 100% | OkCRAP 1 | Ok80% |
| publicHealthBody | 419 to 433 | 1 | 100% | OkCRAP 1 | Ok100% |
| <anonymous:421> | 421 to 421 | 1 | 100% | OkCRAP 1 | Ok100% |
| <anonymous:422> | 422 to 431 | 3 | 100% | OkCRAP 3 | Ok100% |
Imports
It imports app/lib/error-message.mjs. Imported by app/lib/health/checks.server.ts, app/lib/media/rebuild.server.ts, app/lib/operator/sync-tools.server.ts, app/lib/search/ask.server.ts, app/routes/api.health.ts.
Source
import { errorMessage } from "../error-message.mjs";
/**
* A derived index against its source: the sizes, what it lacks and what it holds beyond the source,
* each sorted. Kept apart so a missing key and an extra one cannot cancel out in a count.
*
* @param {Set<string>} expected
* @param {Set<string>} present
*/
export function setDrift(expected, present) {
return {
expected: expected.size,
present: present.size,
missing: [...expected].filter((k) => !present.has(k)).sort(),
extra: [...present].filter((k) => !expected.has(k)).sort(),
};
}
/**
* Both directions summed: a missing record and a stale one are each a wrong answer. Matches the admin badge.
*
* @param {{ expected: number, present: number, missing: string[], stale: string[] }} status
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function askDriftVerdict(status) {
const drift = status.missing.length + status.stale.length;
if (drift === 0) {
return {
ok: true,
detail: `Ask index agrees with D1: ${status.expected} expected, ${status.present} present.`,
};
}
return {
ok: false,
detail:
`Ask index drift ${drift}: ${status.missing.length} missing, ` +
`${status.stale.length} stale, ${status.expected} expected, ` +
`${status.present} present. Repair with sync-ask on /admin/posts.`,
counts: { expected: status.expected, present: status.present },
};
}
/**
* Both directions summed, since they can cancel in a count comparison while both are true. Here R2 is
* the truth and D1 the projection; media-backup-drift is the other way round.
*
* @param {{ expected: number, present: number, missing: string[], extra: string[] }} status
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function mediaDriftVerdict(status) {
const drift = status.missing.length + status.extra.length;
if (drift === 0) {
return {
ok: true,
detail: `Media index agrees with R2 and public/: ${status.expected} expected, ${status.present} present.`,
};
}
return {
ok: false,
detail:
`Media index drift ${drift}: ${status.missing.length} missing, ` +
`${status.extra.length} extra, ${status.expected} expected, ` +
`${status.present} present. Repair with sync_media on the operator API, ` +
`or the rebuild action on /admin/media.`,
counts: { expected: status.expected, present: status.present },
};
}
/**
* The counts travel so zero missing cannot mean zero examined. Mismatched is counted apart from missing:
* a wrong copy, not an absent one, means something rewrote the mirror.
*
* @param {{ objects: number, twins: number, missing: string[], mismatched: string[] }} status
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function mediaBackupDriftVerdict(status) {
const missing = status.missing.length;
const mismatched = status.mismatched.length;
if (status.objects === 0) {
return {
ok: true,
detail:
"MEDIA bucket holds no objects, so the mirror has nothing to hold either. " +
"0 objects, 0 twins, 0 missing: examined nothing rather than verified anything.",
};
}
if (missing === 0 && mismatched === 0) {
return {
ok: true,
detail:
`Every MEDIA object has a byte-identical twin: ${status.objects} objects, ` +
`${status.twins} twins, 0 missing.`,
};
}
return {
ok: false,
detail:
`Media backup drift: ${status.objects} objects, ${status.twins} twins, ` +
`${missing} missing, ${mismatched} mismatched. ` +
`First missing: ${status.missing[0] ?? "none"}. ` +
`First mismatched: ${status.mismatched[0] ?? "none"}. ` +
`Repair with backup_media on the operator API, which only ever copies.`,
counts: { expected: status.objects, present: status.twins },
};
}
/**
* Shared with the sync_posts repair, so what the check calls drift and what the repair repairs agree.
*
* changed a slug present on both sides whose blob sha differs: the file
* moved and the row has not followed (or a row's provenance was
* corrupted, which repairs identically).
* unrowed a file with no row: a post committed from a clone that no sync
* has landed yet, or a lost row.
* unfiled a row with no file: a post deleted from the repository whose
* rows outlived it.
*
* @param {Array<{ slug: string, sha: string }>} files from the Contents
* directory listing, blob sha per markdown file
* @param {Array<{ slug: string, source_blob_sha: string | null }>} rows
* @returns {{ changed: string[], unrowed: string[], unfiled: string[] }}
*/
export function contentDriftCompare(files, rows) {
const rowBySlug = new Map(rows.map((r) => [r.slug, r]));
const fileSlugs = new Set(files.map((f) => f.slug));
const changed = files
.filter((f) => {
const row = rowBySlug.get(f.slug);
return row !== undefined && row.source_blob_sha !== f.sha;
})
.map((f) => f.slug)
.sort();
const unrowed = files
.filter((f) => !rowBySlug.has(f.slug))
.map((f) => f.slug)
.sort();
const unfiled = rows
.filter((r) => !fileSlugs.has(r.slug))
.map((r) => r.slug)
.sort();
return { changed, unrowed, unfiled };
}
/**
* present counts rows in full agreement, so equal totals with one sha changed still read as drift.
*
* @param {Array<{ slug: string, sha: string }>} files
* @param {Array<{ slug: string, source_blob_sha: string | null }>} rows
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function contentDriftVerdict(files, rows) {
return sourceDriftVerdict(files, rows, { label: "Content", noun: "post", tool: "sync_posts" });
}
/**
* The same comparison for the procedure files and the procedures table, so what counts as drift is one
* rule for both.
*
* @param {Array<{ slug: string, sha: string }>} files
* @param {Array<{ slug: string, source_blob_sha: string | null }>} rows
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function procedureDriftVerdict(files, rows) {
return sourceDriftVerdict(files, rows, {
label: "Procedure",
noun: "procedure",
tool: "sync_procedures",
});
}
/**
* The same comparison for the dictionary entry files and the dictionary_entries table.
*
* @param {Array<{ slug: string, sha: string }>} files
* @param {Array<{ slug: string, source_blob_sha: string | null }>} rows
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function dictionaryDriftVerdict(files, rows) {
return sourceDriftVerdict(files, rows, { label: "Dictionary", noun: "dictionary entry", tool: "sync_dictionary" });
}
/**
* The same comparison for the page files and the pages table.
*
* @param {Array<{ slug: string, sha: string }>} files
* @param {Array<{ slug: string, source_blob_sha: string | null }>} rows
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function pageDriftVerdict(files, rows) {
return sourceDriftVerdict(files, rows, { label: "Page", noun: "page", tool: "sync_pages" });
}
/**
* The same comparison for the CV files and the cv table.
*
* @param {Array<{ slug: string, sha: string }>} files
* @param {Array<{ slug: string, source_blob_sha: string | null }>} rows
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function cvDriftVerdict(files, rows) {
return sourceDriftVerdict(files, rows, { label: "CV", noun: "CV", tool: "sync_cv" });
}
/**
* The CV's PDF against the CV D1 holds now: the stored object's fingerprint (custom metadata) against the
* fingerprint of the data. `stored` is null when there is no object and "" when there is one that carries no
* fingerprint (neither is current). Derived store against its source, as the others, repaired by sync_cv_pdf.
*
* @param {{ stored: string | null, expected: string }} sides
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function cvPdfDriftVerdict({ stored, expected }) {
if (stored === expected) {
return { ok: true, detail: `The stored CV PDF was drawn from the CV data D1 holds now (CV data ${expected}).` };
}
const what =
stored === null
? "there is no stored CV PDF"
: stored === ""
? "the stored CV PDF carries no fingerprint"
: `the stored CV PDF was drawn from CV data ${stored}`;
return {
ok: false,
detail: `CV PDF drift 1: ${what}, and D1's CV is CV data ${expected}. Repair with sync_cv_pdf.`,
counts: { expected: 1, present: 0 },
};
}
/**
* The same comparison for the publication files and the publications table.
*
* @param {Array<{ slug: string, sha: string }>} files
* @param {Array<{ slug: string, source_blob_sha: string | null }>} rows
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function publicationDriftVerdict(files, rows) {
return sourceDriftVerdict(files, rows, { label: "Publication", noun: "publication", tool: "sync_publications" });
}
/**
* The same comparison for the roster files and the roster table.
*
* @param {Array<{ slug: string, sha: string }>} files
* @param {Array<{ slug: string, source_blob_sha: string | null }>} rows
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function rosterDriftVerdict(files, rows) {
return sourceDriftVerdict(files, rows, { label: "Roster", noun: "cohort", tool: "sync_roster" });
}
/**
* The same comparison for the phage files and the phages table.
*
* @param {Array<{ slug: string, sha: string }>} files
* @param {Array<{ slug: string, source_blob_sha: string | null }>} rows
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function phageDriftVerdict(files, rows) {
return sourceDriftVerdict(files, rows, { label: "Phage", noun: "phage", tool: "sync_phages" });
}
/**
* The same comparison for the registry files and the registry table. An item is read by its address, `<kind>/<id>`.
*
* @param {Array<{ slug: string, sha: string }>} files
* @param {Array<{ slug: string, source_blob_sha: string | null }>} rows
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function registryDriftVerdict(files, rows) {
return sourceDriftVerdict(files, rows, { label: "Registry", noun: "registry item", tool: "sync_registry" });
}
/**
* The same comparison for content/llms.txt and the settings row /llms.txt is served from: one file, one row.
*
* @param {Array<{ slug: string, sha: string }>} files
* @param {Array<{ slug: string, source_blob_sha: string | null }>} rows
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function llmsDriftVerdict(files, rows) {
return sourceDriftVerdict(files, rows, { label: "llms.txt", noun: "llms.txt", tool: "sync_llms" });
}
/**
* @param {Array<{ slug: string, sha: string }>} files
* @param {Array<{ slug: string, source_blob_sha: string | null }>} rows
* @param {{ label: string, noun: string, tool: string }} words
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
function sourceDriftVerdict(files, rows, { label, noun, tool }) {
const { changed, unrowed, unfiled } = contentDriftCompare(files, rows);
const drift = changed.length + unrowed.length + unfiled.length;
if (drift === 0) {
return {
ok: true,
detail: `D1 agrees with the repository: ${files.length} ${noun} file(s), every blob sha matched by its row.`,
};
}
return {
ok: false,
detail:
`${label} drift ${drift}: ${changed.length} sha-changed, ${unrowed.length} ` +
`file(s) with no row, ${unfiled.length} row(s) with no file, against ` +
`${files.length} ${noun} file(s). Repair with ${tool} on the operator API.`,
counts: { expected: files.length, present: files.length - changed.length - unrowed.length },
};
}
/**
* Counted on the _docsize shadows: COUNT(*) on an external-content fts5 table reads through to its
* content table and never fails. A count that cannot be read FAILS rather than comparing undefined.
*
* @param {Record<string, unknown>} counts
* @returns {{ ok: boolean, detail: string, counts?: { expected: number, present: number } }}
*/
export function ftsEqualityVerdict(counts) {
const NAMES = ["posts", "postsFts", "docs", "identity", "prose"];
const unreadable = NAMES.filter((n) => !Number.isInteger(counts[n]) || Number(counts[n]) < 0);
if (unreadable.length > 0) {
return {
ok: false,
detail:
`FTS counts unreadable: ${unreadable.join(", ")} ` +
`${unreadable.length === 1 ? "is" : "are"} missing or not a whole number. ` +
`A count that cannot be read is not a passing check.`,
};
}
const posts = Number(counts.posts);
const postsFts = Number(counts.postsFts);
const docs = Number(counts.docs);
const identity = Number(counts.identity);
const prose = Number(counts.prose);
const broken = [];
if (posts !== postsFts) broken.push(`posts=${posts} but posts_fts_docsize=${postsFts}`);
if (identity !== docs || prose !== docs) {
broken.push(
`search_docs=${docs} but search_identity_docsize=${identity} and ` +
`search_prose_docsize=${prose}`,
);
}
if (broken.length === 0) {
return {
ok: true,
detail:
`FTS indexes agree: posts=${posts}=posts_fts_docsize, ` +
`search_docs=${docs}=identity=prose.`,
};
}
return {
ok: false,
detail:
`FTS index drift: ${broken.join("; ")}. ` +
`Rebuild with INSERT INTO <index>(<index>) VALUES('rebuild'). ` +
`Do NOT DELETE FROM either index; that corrupts it further.`,
// The first disagreeing pair only; the full five are in detail, which stays off the wire.
counts:
posts !== postsFts
? { expected: posts, present: postsFts }
: { expected: docs, present: identity !== docs ? identity : prose },
};
}
/** Measured: ask-index-drift maxed at 2332 ms over 12 samples, so 3 s clears it without false alarms. */
export const CHECK_TIMEOUT_MS = 3000;
/**
* A timeout is a failed check. It does not cancel the work: only the RESPONSE is bounded, and abandoned
* work keeps accumulating under sustained timeouts.
*
* @param {Promise<{ ok: boolean, detail: string, counts?: { expected: number, present: number } }>} promise
* @param {number} ms
* @param {string} name
* @returns {Promise<{ ok: boolean, detail: string, counts?: { expected: number, present: number } }>}
*/
export function withTimeout(promise, ms, name) {
return new Promise((resolve) => {
const timer = setTimeout(
() =>
resolve({
ok: false,
detail: `check ${name} did not answer within ${ms}ms and is reported failed`,
}),
ms,
);
promise.then(
(value) => {
clearTimeout(timer);
resolve(value);
},
(error) => {
clearTimeout(timer);
resolve({
ok: false,
detail: `check threw: ${errorMessage(error)}`,
});
},
);
});
}
/**
* Detail strings never reach this unauthenticated wire: they carry an R2 object key and shadow table
* names. A FAILING check carries its two counts, so a flap can be sized; a passing one, name and ok.
*
* @param {{ checks: Array<{ name: string, ok: boolean, counts?: { expected: number, present: number } }> }} run
* @returns {{ ok: boolean, checks: Array<{ name: string, ok: boolean, expected?: number, present?: number }> }}
*/
export function publicHealthBody(run) {
return {
ok: run.checks.every((c) => c.ok),
checks: run.checks.map((c) => {
// Field by field, not spread, so a field added to HealthCheck later cannot leak onto the wire.
if (c.ok || !c.counts) return { name: c.name, ok: c.ok };
return {
name: c.name,
ok: c.ok,
expected: c.counts.expected,
present: c.counts.present,
};
}),
};
}