// src/pre-registration.ts
function canonicalize(v) {
  if (v === null || typeof v !== "object") return v;
  if (Array.isArray(v)) return v.map(canonicalize);
  const keys = Object.keys(v).sort();
  const out = {};
  for (const k of keys) out[k] = canonicalize(v[k]);
  return out;
}
async function hashJson(obj) {
  const canonical = canonicalize(obj);
  const bytes = new TextEncoder().encode(JSON.stringify(canonical));
  const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
  return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
}
async function signManifest(m) {
  const hash = await hashJson(m);
  return { ...m, contentHash: hash, algo: "sha256-content" };
}
async function verifyManifest(m) {
  const { contentHash, algo: _algo, ...rest } = m;
  void _algo;
  const resigned = await signManifest(rest);
  return resigned.contentHash === contentHash;
}
async function evaluateHypothesis(manifest, observed) {
  if (!await verifyManifest(manifest)) {
    throw new Error("evaluateHypothesis: manifest content hash mismatch (tampered)");
  }
  const reasons = [];
  const directionOk = manifest.direction === "increase" ? observed.effect > 0 : observed.effect < 0;
  if (!directionOk) reasons.push("wrong_direction");
  if (Math.abs(observed.effect) < manifest.minEffect) reasons.push("effect_too_small");
  if (observed.pValue >= manifest.alpha) reasons.push("not_significant");
  if (observed.n < manifest.preRegisteredN) reasons.push("undersampled");
  return {
    manifest,
    observedN: observed.n,
    observedEffect: observed.effect,
    observedPValue: observed.pValue,
    confirmed: reasons.length === 0,
    rejectionReasons: reasons
  };
}

export {
  canonicalize,
  hashJson,
  signManifest,
  verifyManifest,
  evaluateHypothesis
};
//# sourceMappingURL=chunk-VSMTAMNK.js.map