// Stamps every harness event with run identity, a monotonic seq, and a clock timestamp,
// then forwards it to the sink. SENSITIVE fields (rationale, modelResponse, diff) are
// redacted before forwarding UNLESS the sink retains raw content for replay (ADR-0004 D6).
import { redact } from "@oscharko-dev/keiko-model-gateway";
function redactReasoningTrace(event) {
    return {
        ...event,
        rationale: redact(event.rationale),
        ...(event.modelResponse === undefined ? {} : { modelResponse: redact(event.modelResponse) }),
    };
}
function redactRunCompleted(event) {
    // WHY: report and patchDiff carry full model output; keep known secret formats out of every
    // sink that does not explicitly retain raw content for replay.
    return {
        ...event,
        report: redact(event.report),
        ...(event.patchDiff === undefined ? {} : { patchDiff: redact(event.patchDiff) }),
    };
}
function redactRunFailed(event) {
    const failure = {
        ...event.failure,
        message: redact(event.failure.message),
        ...(event.failure.detail === undefined ? {} : { detail: redact(event.failure.detail) }),
    };
    return { ...event, failure };
}
const REDACTORS = {
    "reasoning:trace": redactReasoningTrace,
    "patch:proposed": (event) => ({ ...event, diff: redact(event.diff) }),
    "model:call:failed": (event) => ({ ...event, message: redact(event.message) }),
    "tool:call:failed": (event) => ({ ...event, message: redact(event.message) }),
    "verification:result": (event) => ({ ...event, detail: redact(event.detail) }),
    "run:completed": redactRunCompleted,
    "run:cancelled": (event) => event.reason === undefined ? event : { ...event, reason: redact(event.reason) },
    "run:failed": redactRunFailed,
};
function redactSensitive(event) {
    const redactor = REDACTORS[event.type];
    return redactor === undefined ? event : redactor(event);
}
export class Emitter {
    sinks;
    clock;
    runId;
    fingerprint;
    seq = 0;
    // Fans every event out to all sinks. Each sink receives raw SENSITIVE fields only if it
    // declares `retainsRawContent`; otherwise it receives a redacted copy.
    constructor(sinks, clock, runId, fingerprint) {
        this.sinks = sinks;
        this.clock = clock;
        this.runId = runId;
        this.fingerprint = fingerprint;
    }
    emit(body) {
        this.seq += 1;
        const event = {
            schemaVersion: "1",
            runId: this.runId,
            fingerprint: this.fingerprint,
            seq: this.seq,
            ts: this.clock.now(),
            ...body,
        };
        const redacted = redactSensitive(event);
        for (const sink of this.sinks) {
            sink.emit(sink.retainsRawContent === true ? event : redacted);
        }
    }
}
