/* RFC-1037: Compensation verifier — runs verification probes in parallel using Promise.allSettled, stores results in CompensationStore, and records compensation events in Bordbuch. Probes execute in the build pipeline (Node.js environment). Does not implement effect classification — that lives in effect-classifier.ts. Does not implement command registration — that lives in effects.module.ts. Does not implement Bordbuch writing directly — delegates to bordbuch-io via context. RFC-1037: initial implementation — CompensationVerifier with parallel probe execution. */ import { lookup } from "node:dns/promises"; import { request } from "node:https"; import { request as httpRequest } from "node:http"; import type { CompensationAction, CompensationProbe, CompensationResult, ProbeResult, } from "@warpgogol/werkstatt-shared/component"; import type { Sha256Digest } from "@warpgogol/werkstatt-shared/fingerprint"; import type { CompensationStore } from "./compensation-store.ts"; import type { KernelRuntimeContext } from "@warpgogol/werkstatt-shared/kernel"; export class CompensationVerifier { private readonly store: CompensationStore; private readonly context: KernelRuntimeContext; private readonly locks: Map> = new Map(); constructor(store: CompensationStore, context: KernelRuntimeContext) { this.store = store; this.context = context; } async verify( operationHash: Sha256Digest, compensationHash: Sha256Digest, action: CompensationAction, ): Promise { const lockKey = operationHash; const existing = this.locks.get(lockKey); if (existing) { await existing; } let resolveLock!: () => void; const lockPromise = new Promise((resolve) => { resolveLock = resolve; }); this.locks.set(lockKey, lockPromise); try { const probeResults = await this.runProbes(action); const verified = probeResults.every((r) => r.passed); const failureReason = verified ? undefined : probeResults.find((r) => !r.passed)?.probe ? `${probeResults.filter((r) => !r.passed).length} probe(s) failed` : "unknown failure"; const result: CompensationResult = { operationHash, compensationHash, verified, probeResults, verifiedAt: new Date().toISOString(), failureReason, }; this.store.save(result); return result; } finally { resolveLock(); this.locks.delete(lockKey); } } private async runProbes(action: CompensationAction): Promise { const globalTimeout = action.verificationTimeoutMs; const probePromises = action.verificationProbes.map((probe) => this.runSingleProbe(probe)); const globalTimeoutPromise = new Promise((resolve) => { setTimeout(() => { resolve( action.verificationProbes.map((probe) => ({ probe, passed: false, latencyMs: globalTimeout, actualValue: undefined, })), ); }, globalTimeout); }); const settled = await Promise.race([ Promise.allSettled(probePromises), globalTimeoutPromise.then((results) => ({ kind: "timeout", results }) as const), ]); if (Array.isArray(settled)) { return settled.map((result, index) => { const probe = action.verificationProbes[index]; if (result.status === "fulfilled") { return result.value; } return { probe, passed: false, latencyMs: 0, actualValue: undefined, }; }); } return settled.results; } private async runSingleProbe(probe: CompensationProbe): Promise { const start = Date.now(); try { const result = await this.executeProbe(probe); const latencyMs = Date.now() - start; return { probe, passed: result.passed, actualValue: result.actualValue, latencyMs, }; } catch (err) { const latencyMs = Date.now() - start; return { probe, passed: false, latencyMs, actualValue: err instanceof Error ? err.message : String(err), }; } } private async executeProbe( probe: CompensationProbe, ): Promise<{ passed: boolean; actualValue?: string }> { switch (probe.type) { case "dns-resolved": return this.executeDnsProbe(probe); case "http-status": return this.executeHttpStatusProbe(probe); case "cdn-cleared": return this.executeCdnClearedProbe(probe); case "mirror-synced": return this.executeMirrorSyncedProbe(probe); case "custom": return this.executeCustomProbe(probe); default: { const _exhaustive: never = probe.type; throw new Error(`unknown probe type: ${_exhaustive}`); } } } private async executeDnsProbe( probe: CompensationProbe, ): Promise<{ passed: boolean; actualValue?: string }> { try { const records = await lookup(probe.target); const actual = records.address; return { passed: actual === probe.expected, actualValue: actual }; } catch (err) { return { passed: false, actualValue: err instanceof Error ? err.message : String(err) }; } } private async executeHttpStatusProbe( probe: CompensationProbe, ): Promise<{ passed: boolean; actualValue?: string }> { return new Promise((resolve) => { const url = new URL(probe.target); const isHttps = url.protocol === "https:"; const reqFn = isHttps ? request : httpRequest; const req = reqFn( { hostname: url.hostname, port: url.port, path: url.pathname + url.search, method: "HEAD", timeout: probe.timeoutMs, }, (res) => { const status = String(res.statusCode ?? 0); resolve({ passed: status === probe.expected, actualValue: status }); }, ); req.on("error", (err) => { resolve({ passed: false, actualValue: err.message }); }); req.on("timeout", () => { req.destroy(); resolve({ passed: false, actualValue: "timeout" }); }); req.end(); }); } private async executeCdnClearedProbe( probe: CompensationProbe, ): Promise<{ passed: boolean; actualValue?: string }> { return new Promise((resolve) => { const url = new URL(probe.target); const isHttps = url.protocol === "https:"; const reqFn = isHttps ? request : httpRequest; const req = reqFn( { hostname: url.hostname, port: url.port, path: url.pathname + url.search, method: "HEAD", timeout: probe.timeoutMs, }, (res) => { const etag = res.headers["etag"] ?? ""; resolve({ passed: etag === probe.expected, actualValue: String(etag) }); }, ); req.on("error", (err) => { resolve({ passed: false, actualValue: err.message }); }); req.on("timeout", () => { req.destroy(); resolve({ passed: false, actualValue: "timeout" }); }); req.end(); }); } private async executeMirrorSyncedProbe( _probe: CompensationProbe, ): Promise<{ passed: boolean; actualValue?: string }> { return { passed: false, actualValue: "mirror-synced probe requires customVerifyCommand" }; } private async executeCustomProbe( probe: CompensationProbe, ): Promise<{ passed: boolean; actualValue?: string }> { if (!probe.customVerifyCommand) { return { passed: false, actualValue: "custom probe requires customVerifyCommand" }; } return { passed: false, actualValue: `custom command "${probe.customVerifyCommand}" not invoked in build pipeline`, }; } }