/**
 * instrumentation.ts — stdout JSON event emitter for olam-cli.
 *
 * Phase 1b A3 of olam-host-suite-phase-1b-k3s-beta-flavour (plan
 * ~/.claude/plans/olam-host-suite-phase-1b-k3s-beta-flavour.md).
 *
 * Canonical event schema (Decision 21 — `olam.instr.v1`):
 *   {
 *     "schema": "olam.instr.v1",
 *     "event": "substrate.set" | "upgrade.complete",
 *     "install_id": "<uuid-v4-from-config>",
 *     "ts": "<ISO-8601-UTC>",
 *     <event-specific-fields>
 *   }
 *
 * Emission target: **stderr**, newline-delimited, each line prefixed with
 * `OLAM_INSTR ` so consumers can grep-distinguish from other stderr output.
 *
 * Why stderr (and not stdout)? olam-cli's existing stdout-JSON contracts
 * (e.g. `olam status --json`, `olam doctor --json`) reserve stdout for
 * command output that consumers parse positionally. Mixing instrumentation
 * into stdout breaks those contracts. stderr keeps the emitter
 * grep-distinguishable AND segregated from the data-plane output.
 *
 * Consumers: month-6 aggregator script (`scripts/aggregate-substrate-events.mjs`,
 * D20) groups events by `install_id` for Falsifiable signal thresholds 1+4.
 *
 * Defensive contract:
 *   - emit() MUST NOT throw if the config can't be read; falls back to a
 *     placeholder install_id ('unknown') + emits a one-line stderr WARN.
 *   - Schema is versioned (`olam.instr.v1`); v2 fields land additively.
 *     Consumers MUST tolerate unknown fields.
 */
import { readConfig } from './config.js';
export const INSTRUMENTATION_SCHEMA = 'olam.instr.v1';
export const INSTRUMENTATION_PREFIX = 'OLAM_INSTR ';
function nowIso(now) {
    const d = now ? now() : new Date();
    return d.toISOString();
}
function resolveInstallId(opts) {
    try {
        if (opts.installIdProvider)
            return opts.installIdProvider();
        const cfg = readConfig();
        return cfg.install_id;
    }
    catch {
        return 'unknown';
    }
}
function writeLine(stderr, payload) {
    try {
        const line = `${INSTRUMENTATION_PREFIX}${JSON.stringify(payload)}\n`;
        stderr.write(line);
    }
    catch (err) {
        // emit must never throw; surface the failure tersely to stderr.
        try {
            stderr.write(`[WARN] olam instrumentation emit failed: ${err instanceof Error ? err.message : String(err)}\n`);
        }
        catch {
            // give up; emitter contract is best-effort.
        }
    }
}
/**
 * Emit a `substrate.set` event. Called by `olam substrate set` ONLY on success
 * (failure paths emit nothing — by design; thresholds count successful switches).
 *
 * @param payload — substrate + optional flavor
 * @param opts — test-only injection points (stderr / now / installIdProvider)
 */
export function emitSubstrateSet(payload, opts = {}) {
    const event = {
        schema: INSTRUMENTATION_SCHEMA,
        event: 'substrate.set',
        install_id: resolveInstallId(opts),
        ts: nowIso(opts.now),
        substrate: payload.substrate,
        ...(payload.flavor !== undefined ? { flavor: payload.flavor } : {}),
    };
    writeLine(opts.stderr ?? process.stderr, event);
}
/**
 * Emit an `upgrade.complete` event. Called by Phase C C2's substrate-aware
 * `olam upgrade` ONLY on success.
 *
 * @param payload — substrate + duration_ms (and optional flavor)
 * @param opts — test-only injection points
 */
export function emitUpgradeComplete(payload, opts = {}) {
    const event = {
        schema: INSTRUMENTATION_SCHEMA,
        event: 'upgrade.complete',
        install_id: resolveInstallId(opts),
        ts: nowIso(opts.now),
        substrate: payload.substrate,
        duration_ms: payload.duration_ms,
        ...(payload.flavor !== undefined ? { flavor: payload.flavor } : {}),
    };
    writeLine(opts.stderr ?? process.stderr, event);
}
//# sourceMappingURL=instrumentation.js.map