Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 45 additions & 34 deletions scripts/verify-order.mjs
Original file line number Diff line number Diff line change
@@ -1,20 +1,46 @@
#!/usr/bin/env node
import { execSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';

const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
const FIXTURE_PATH = join(ROOT, 'src', 'shared', 'data', 'expectedProtocolOrder.json');

// 1. Read old drugMasterlist.ts from git HEAD
// Baseline must be a revision where drugMasterlist.ts still holds the hand-typed
// records. HEAD stops being that as soon as this change is committed, so default to
// origin/main and allow an override: `node scripts/verify-order.mjs <ref>`.
const BASELINE_REF = process.argv[2] || 'origin/main';
const oldFileContent = execSync(
`GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 git show ${BASELINE_REF}:src/shared/data/drugMasterlist.ts`,
{ encoding: 'utf8' }
);
// 1. Read and validate expectedProtocolOrder.json fixture
let fixture;
try {
const fixtureContent = readFileSync(FIXTURE_PATH, 'utf8');
fixture = JSON.parse(fixtureContent);
} catch (err) {
console.error(`BROKEN CHECK: Failed to read or parse fixture at ${FIXTURE_PATH}: ${err.message}`);
process.exit(2);
}

const EXPECTED_PROTOCOL_COUNT = 116;
if (
!fixture ||
typeof fixture !== 'object' ||
!Array.isArray(fixture.order) ||
!Number.isInteger(fixture.count) ||
fixture.count !== EXPECTED_PROTOCOL_COUNT ||
fixture.order.length !== EXPECTED_PROTOCOL_COUNT
) {
console.error(
`BROKEN CHECK: fixture is malformed or count mismatch (count: ${fixture?.count}, order.length: ${fixture?.order?.length}).\n` +
`Expected an object with 'order' array and matching integer 'count' equal to ${EXPECTED_PROTOCOL_COUNT}.`
);
process.exit(2);
}

for (let i = 0; i < fixture.order.length; i++) {
const item = fixture.order[i];
if (!item || typeof item.drugName !== 'string' || typeof item.testType !== 'string' || typeof item.protocolLabel !== 'string') {
console.error(`BROKEN CHECK: fixture entry at index ${i} is malformed: ${JSON.stringify(item)}`);
process.exit(2);
}
}

const expectedTuples = fixture.order;

function extractTuples(fileContent) {
const tuples = [];
Expand All @@ -30,21 +56,6 @@ function extractTuples(fileContent) {
return tuples;
}

const oldTuples = extractTuples(oldFileContent);

// A baseline that yields almost no records means the ref is not the pre-change file
// (e.g. it already points at the thin module). Fail loudly as a broken check rather
// than silently reporting every position as a mismatch.
const MIN_EXPECTED_BASELINE = 50;
if (oldTuples.length < MIN_EXPECTED_BASELINE) {
console.error(
`BROKEN CHECK: baseline ref '${BASELINE_REF}' yielded only ${oldTuples.length} records ` +
`(expected >= ${MIN_EXPECTED_BASELINE}).\nThis is not a reordering failure — the baseline is wrong. ` +
`Pass a ref where drugMasterlist.ts still holds the hand-typed records.`
);
process.exit(2);
}

// 2. Read generated and dream-only files to reconstruct the merged DRUG_MASTERLIST order
const generatedContent = readFileSync(join(ROOT, 'src', 'shared', 'data', 'drugMasterlist.generated.ts'), 'utf8');
const dreamOnlyContent = readFileSync(join(ROOT, 'src', 'shared', 'data', 'dreamOnlyProtocols.ts'), 'utf8');
Expand All @@ -61,7 +72,7 @@ function findGenTuple(drugName, testType, label) {
}

// Reconstruct merged array order exactly as drugMasterlist.ts does
const newTuples = [
const actualTuples = [
findGenTuple('Cis-atracurium', 'skin'),
findGenTuple('Rocuronium', 'skin'),
findGenTuple('Pancuronium', 'skin'),
Expand All @@ -77,21 +88,21 @@ const newTuples = [
console.log('================================================================================');
console.log('DRUG MASTERLIST POSITIONAL ORDER VERIFICATION');
console.log('================================================================================');
console.log(`OLD (${BASELINE_REF}) record count: ${oldTuples.length}`);
console.log(`NEW (merged) record count: ${newTuples.length}`);
console.log(`EXPECTED (fixture) record count: ${expectedTuples.length}`);
console.log(`ACTUAL (merged) record count: ${actualTuples.length}`);

let mismatches = 0;
const total = Math.max(oldTuples.length, newTuples.length);
const total = Math.max(expectedTuples.length, actualTuples.length);

for (let i = 0; i < total; i++) {
const o = oldTuples[i];
const n = newTuples[i];
const exp = expectedTuples[i];
const act = actualTuples[i];

if (!o || !n || o.drugName !== n.drugName || o.testType !== n.testType || o.protocolLabel !== n.protocolLabel) {
if (!exp || !act || exp.drugName !== act.drugName || exp.testType !== act.testType || exp.protocolLabel !== act.protocolLabel) {
mismatches++;
console.error(`MISMATCH at index ${i}:`);
console.error(` OLD: ${JSON.stringify(o)}`);
console.error(` NEW: ${JSON.stringify(n)}`);
console.error(` EXPECTED: ${JSON.stringify(exp)}`);
console.error(` ACTUAL: ${JSON.stringify(act)}`);
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/shared/data/drugMasterlist.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const GENERATED_PROTOCOLS: DrugProtocol[] = [
protocolLabel: "IV",
sourceSlug: "cis-atracurium",
underReview: false,
lastReviewed: "2026-08-20",
lastReviewed: "2026-03-28",
},
{
id: "iv",
Expand All @@ -66,7 +66,7 @@ export const GENERATED_PROTOCOLS: DrugProtocol[] = [
protocolLabel: "IV",
sourceSlug: "pancuronium",
underReview: false,
lastReviewed: "2026-08-20",
lastReviewed: "2026-03-28",
},
{
id: "iv",
Expand All @@ -81,7 +81,7 @@ export const GENERATED_PROTOCOLS: DrugProtocol[] = [
protocolLabel: "IV",
sourceSlug: "rocuronium",
underReview: false,
lastReviewed: "2026-08-20",
lastReviewed: "2026-03-28",
},
{
id: "iv",
Expand All @@ -96,7 +96,7 @@ export const GENERATED_PROTOCOLS: DrugProtocol[] = [
protocolLabel: "IV",
sourceSlug: "suxamethonium",
underReview: false,
lastReviewed: "2026-08-20",
lastReviewed: "2026-03-28",
},
{
id: "iv",
Expand All @@ -111,6 +111,6 @@ export const GENERATED_PROTOCOLS: DrugProtocol[] = [
protocolLabel: "IV",
sourceSlug: "vecuronium",
underReview: false,
lastReviewed: "2026-08-20",
lastReviewed: "2026-03-28",
},
];
2 changes: 1 addition & 1 deletion src/shared/data/drugMasterlist.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ describe('drugMasterlist diluents & snapshot data', () => {
const rocuronium = getSkinProtocolsForDrug('Rocuronium')[0];
expect(rocuronium.sourceSlug).toBe('rocuronium');
expect(rocuronium.underReview).toBe(false);
expect(rocuronium.lastReviewed).toBe('2026-08-20');
expect(rocuronium.lastReviewed).toBe('2026-03-28');
expect(rocuronium.id).toBe('iv');
});

Expand Down
24 changes: 12 additions & 12 deletions src/shared/data/protocols.snapshot.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"schema_version": "1.0",
"generated_at": "2026-08-20T09:16:09Z",
"source_commit": "6d12cec",
"generated_at": "2026-08-20T11:45:36Z",
"source_commit": "254b399",
"drugs": [
{
"slug": "cefazolin",
Expand Down Expand Up @@ -63,8 +63,8 @@
{
"slug": "cis-atracurium",
"title": "Cis-atracurium",
"version": "1.3",
"last_reviewed": "2026-08-20",
"version": "1.4",
"last_reviewed": "2026-03-28",
"dream": {
"category": "Muscle Relaxants"
},
Expand Down Expand Up @@ -97,8 +97,8 @@
{
"slug": "pancuronium",
"title": "Pancuronium",
"version": "1.3",
"last_reviewed": "2026-08-20",
"version": "1.4",
"last_reviewed": "2026-03-28",
"dream": {
"category": "Muscle Relaxants"
},
Expand Down Expand Up @@ -136,8 +136,8 @@
{
"slug": "rocuronium",
"title": "Rocuronium",
"version": "1.3",
"last_reviewed": "2026-08-20",
"version": "1.4",
"last_reviewed": "2026-03-28",
"dream": {
"category": "Muscle Relaxants"
},
Expand Down Expand Up @@ -175,8 +175,8 @@
{
"slug": "suxamethonium",
"title": "Suxamethonium",
"version": "1.3",
"last_reviewed": "2026-08-20",
"version": "1.4",
"last_reviewed": "2026-03-28",
"dream": {
"category": "Muscle Relaxants"
},
Expand Down Expand Up @@ -219,8 +219,8 @@
{
"slug": "vecuronium",
"title": "Vecuronium",
"version": "1.3",
"last_reviewed": "2026-08-20",
"version": "1.4",
"last_reviewed": "2026-03-28",
"dream": {
"category": "Muscle Relaxants"
},
Expand Down
Loading