← back to Homesonspec

packages/validation/src/engine.ts

42 lines

import type {
  RuleContext,
  StagedCandidate,
  ValidationEventInput,
  ValidationOutcome,
  ValidationRule,
} from "./types";

/**
 * Run every applicable rule and fold the results into one verdict.
 * Deterministic: same record + same DB state → same verdict, always.
 *
 *   any failed error  → rejected
 *   any failed review → needs_review
 *   otherwise         → publishable (failed warns log but don't block)
 */
export async function runValidation(
  record: StagedCandidate,
  rules: ValidationRule[],
  ctx: RuleContext,
): Promise<ValidationOutcome> {
  const events: ValidationEventInput[] = [];

  for (const rule of rules) {
    if (!rule.entityTypes.includes(record.entityType)) continue;
    const result = await rule.check(record, ctx);
    events.push({
      ruleId: rule.id,
      severity: rule.severity,
      passed: result.passed,
      message: result.passed ? undefined : result.message,
      details: result.passed ? undefined : result.details,
    });
  }

  const failedError = events.some((e) => !e.passed && e.severity === "error");
  const failedReview = events.some((e) => !e.passed && e.severity === "review");

  const verdict = failedError ? "rejected" : failedReview ? "needs_review" : "publishable";
  return { events, verdict };
}