marmar-context / web / context / scripts / live-evaluation.mjs
live-evaluation.mjs
Raw
import fs from "node:fs/promises";
const base = process.env.CONTEXT_TEST_ORIGIN || "http://127.0.0.1:4191";
if (!/^http:\/\/(127\.0\.0\.1|localhost):4191$/.test(base))
  throw new Error("Use the local Context server.");
const call = async (path, body) => {
  const response = await fetch(
    base + "/api/" + path,
    body
      ? {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(body),
          signal: AbortSignal.timeout(60000),
        }
      : undefined,
  );
  const data = await response.json();
  return { ok: response.ok, status: response.status, data };
};
const health = (await call("status")).data;
if (!health.modelConfigured)
  throw new Error("Connect the model through the demo interface first.");
const cases = (await call("cases")).data;
const report = {
  runAt: new Date().toISOString(),
  model: health.model,
  engine: health.engineVersion,
  scope: "Live synthetic integration checks, not clinical validation",
  cases: [],
};
for (const scenario of cases) {
  const row = { id: scenario.id, passed: false };
  const started = performance.now();
  try {
    const extraction = await call("extract", {
      sources: scenario.sources,
      syntheticOnly: true,
      useModel: true,
      freshModel: true,
    });
    if (!extraction.ok) throw new Error(extraction.data.error);
    const draft = extraction.data;
    row.mode = draft.mode;
    row.strategy = draft.strategy;
    row.providerCalls = draft.metrics?.providerCalls;
    if (draft.mode === "local" && draft.metrics?.providerCalls !== 0)
      throw new Error("Incorrect structured-reader telemetry");
    row.extractionMs = draft.durationMs;
    row.attempts = draft.attempts ?? 0;
    row.factCount = draft.facts.length;
    const review = Object.fromEntries(
      draft.facts.map((f) => [f.id, "include"]),
    );
    const payload = {
      sources: scenario.sources,
      review,
      fingerprint: draft.fingerprint,
      acknowledgeUnparsed: Boolean(
        draft.sourceReviewRequired || draft.unparsed.length,
      ),
      syntheticOnly: true,
      ...(draft.id ? { draftId: draft.id } : {}),
    };
    if (scenario.id === "conflicting-records") {
      const blocked = await call("assess", payload);
      row.conflictBlocked =
        !blocked.ok && /[Cc]onflict/.test(blocked.data.error);
      if (!row.conflictBlocked)
        throw new Error("Conflicting medication records were not blocked");
      const rejected = draft.facts.find(
        (f) => f.sourceId === "fatima-clinic" && f.kind === "medicine",
      );
      review[rejected.id] = "exclude";
    }
    const checked = await call("assess", payload);
    if (!checked.ok) throw new Error(checked.data.error);
    row.ruleIds = checked.data.contextual.findings.map((f) => f.ruleId);
    row.addedRuleIds = checked.data.addedRuleIds;
    const expected =
      scenario.id === "allergy-context"
        ? "allergy-penicillin"
        : "lab-metformin-egfr-45";
    if (!row.addedRuleIds.includes(expected))
      throw new Error("Expected contextual finding was absent");
    row.passed = true;
  } catch (error) {
    row.error = error.message;
  }
  row.totalMs = Math.round(performance.now() - started);
  report.cases.push(row);
  console.log(JSON.stringify(row));
}
report.passed = report.cases.filter((r) => r.passed).length;
report.total = report.cases.length;
const target = process.argv[2] || "validation/live-latest.json";
await fs.writeFile(target, JSON.stringify(report, null, 2) + "\n");
console.log(`Saved ${target}: ${report.passed}/${report.total} passed`);
process.exitCode = report.passed === report.total ? 0 : 1;