// SPEC: PJ2026-01060508 Web哨兵 draft-2026-07-12-p17-monitor-central-persistence.
// Responsibility: Host PostgreSQL-backed Monitor terminal ingest, bounded read models, and health contracts.
import { createHash } from "node:crypto";
import postgres from "postgres";

export const MONITOR_CENTRAL_SPEC_REF = "PJ2026-01060508 Web哨兵 draft-2026-07-12-p17-monitor-central-persistence";
export const MONITOR_CENTRAL_SCHEMA_VERSION = "2026-07-12-p17-3";

export interface MonitorScope {
  readonly sentinelId?: string;
  readonly node?: string;
  readonly lane?: string;
}

export interface MonitorArtifactLocator {
  readonly ownerNode: string;
  readonly ownerLane: string;
  readonly ownerPvc: string;
  readonly stateDir: string;
  readonly relativePath: string;
  readonly sha256: string;
  readonly sizeBytes: number;
  readonly kind: string;
  readonly reachable: boolean;
}

export interface MonitorCentralIngest {
  readonly sentinelId: string;
  readonly node: string;
  readonly lane: string;
  readonly runId: string;
  readonly updatedAt?: string;
  readonly status?: string;
  readonly payload: Record<string, unknown>;
  readonly payloadHash?: string;
  readonly findings?: readonly Record<string, unknown>[];
  readonly artifactLocators?: readonly MonitorArtifactLocator[];
  readonly timeline?: readonly Record<string, unknown>[];
}

export interface MonitorRun extends Required<MonitorScope> {
  readonly runId: string;
  readonly updatedAt: string;
  readonly status: string;
  readonly payloadHash: string;
}

export interface MonitorCentralStore {
  close(): Promise<void>;
  migrate(): Promise<void>;
  ping(): Promise<void>;
  schemaVersion(): Promise<string | null>;
  capability(): Promise<{ readonly ingest: boolean; readonly query: boolean }>;
  ingest(input: NormalizedMonitorCentralIngest): Promise<{ readonly disposition: "inserted" | "idempotent" }>;
  importSource(manifest: MonitorImportManifest, inputs: readonly NormalizedMonitorCentralIngest[], runtimeMetadata?: readonly MonitorRuntimeMetadata[]): Promise<{ readonly disposition: "inserted" | "idempotent"; readonly runs: readonly { readonly disposition: "inserted" | "idempotent" }[] }>;
  runtimeMetadata(scope: Required<MonitorScope>): Promise<readonly MonitorRuntimeMetadata[]>;
  updateArtifactAvailability(scope: Required<MonitorScope>, runId: string, locatorIndex: number, reachable: boolean): Promise<void>;
  overview(scope: MonitorScope): Promise<Record<string, unknown>>;
  monitorWorkspace(scope: MonitorScope, options: MonitorWorkspaceQueryOptions): Promise<MonitorWorkspaceQueryResult>;
  runs(scope: MonitorScope, options: RunQueryOptions): Promise<readonly MonitorRun[]>;
  run(scope: Required<MonitorScope>, runId: string): Promise<Record<string, unknown> | null>;
  view(scope: Required<MonitorScope>, runId: string, view: string): Promise<Record<string, unknown> | null>;
  findings(scope: MonitorScope, options: FindingQueryOptions): Promise<readonly Record<string, unknown>[]>;
}

export interface NormalizedMonitorCentralIngest extends Required<Omit<MonitorCentralIngest, "payloadHash">> {
  readonly payloadHash: string;
}

export interface MonitorImportManifest {
  readonly manifestId: string;
  readonly sourceFingerprint: string;
  readonly rowCount: number;
}

export interface MonitorRuntimeMetadata extends Required<MonitorScope> {
  readonly key: string;
  readonly value: unknown;
  readonly updatedAt: string;
}

interface RunCursor {
  readonly updatedAt: string;
  readonly runId: string;
}

interface FindingCursor extends RunCursor {
  readonly findingIndex: number;
}

export interface RunQueryOptions {
  readonly limit: number;
  readonly cursor: RunCursor | null;
}

export interface FindingQueryOptions {
  readonly limit: number;
  readonly cursor: FindingCursor | null;
}

interface MonitorWorkspaceQueryOptions extends RunQueryOptions {
  readonly status?: string;
  readonly from?: string;
  readonly to?: string;
}

interface MonitorWorkspaceRun extends MonitorRun { readonly findingCount: number; }
interface MonitorWorkspaceQueryResult { readonly items: readonly MonitorWorkspaceRun[]; readonly nextCursor: string | null; readonly totalRuns: number; readonly findingCount: number; readonly statusCounts: Readonly<Record<string, number>>; readonly latestSuccessAt: string | null; readonly latestFailureAt: string | null; }

export interface MonitorCentralService {
  ingest(input: MonitorCentralIngest): Promise<Record<string, unknown>>;
  health(): Promise<Record<string, unknown>>;
  fetch(request: Request): Promise<Response>;
}

export interface MonitorCentralServiceOptions {
  readonly databaseUrl?: string | null;
  readonly store?: MonitorCentralStore;
  readonly pageSize?: number;
  readonly postgres?: PostgresMonitorCentralStoreOptions;
}

export interface PostgresMonitorCentralStoreOptions {
  readonly poolMax: number;
  readonly idleTimeoutSeconds: number;
}

export class MonitorCentralConfigurationError extends Error {
  readonly code = "monitor_central_database_url_missing";

  constructor() {
    super("Monitor central service requires an explicit DATABASE_URL");
    this.name = "MonitorCentralConfigurationError";
  }

  toJSON(): Record<string, unknown> {
    return { ok: false, error: { code: this.code, message: this.message }, valuesRedacted: true };
  }
}

export function createMonitorCentralService(options: MonitorCentralServiceOptions = {}): MonitorCentralService {
  const pageSize = requirePositiveInteger(options.pageSize, "monitor_central_page_size_missing");
  const store = options.store ?? createPostgresMonitorCentralStore(requireDatabaseUrl(options.databaseUrl), requirePostgresOptions(options.postgres));
  const ingest = async (input: MonitorCentralIngest) => {
    const normalized = normalizeMonitorCentralIngest(input);
    const result = await store.ingest(normalized);
    return { ok: true, ...result, identity: identityOf(normalized), payloadHash: normalized.payloadHash, valuesRedacted: true };
  };
  const health = async () => {
    const checks: Record<string, unknown>[] = [{ name: "configuration", ok: true, valuesRedacted: true }];
    try {
      await store.ping();
      checks.push({ name: "postgres", ok: true, valuesRedacted: true });
      const schemaVersion = await store.schemaVersion();
      checks.push({ name: "schema", ok: schemaVersion === MONITOR_CENTRAL_SCHEMA_VERSION, version: schemaVersion, valuesRedacted: true });
      const capability = await store.capability();
      checks.push({ name: "ingest", ok: capability.ingest, valuesRedacted: true });
      checks.push({ name: "query", ok: capability.query, valuesRedacted: true });
    } catch (error) {
      checks.push({ name: "postgres", ok: false, code: "postgres_unavailable", message: errorMessage(error), valuesRedacted: true });
    }
    return { ok: checks.every((item) => item.ok === true), checks, valuesRedacted: true };
  };
  const fetch = async (request: Request): Promise<Response> => {
    const url = new URL(request.url);
    try {
      if (request.method === "POST" && url.pathname === "/api/ingest") {
        const result = await ingest(await requestRecord(request));
        return json(result, result.disposition === "inserted" ? 201 : 200);
      }
      if (request.method === "GET" && url.pathname === "/health") {
        const result = await health();
        return json(result, result.ok === true ? 200 : 503);
      }
      if (request.method === "GET" && url.pathname === "/api/overview") return json({ ok: true, overview: await store.overview(scopeFrom(url)), valuesRedacted: true });
      if (request.method === "GET" && url.pathname === "/api/monitor/workspace") return json(await monitorWorkspace(store, url, pageSize));
      const monitorRunMatch = request.method === "GET" ? url.pathname.match(/^\/api\/monitor\/runs\/([^/]+)$/u) : null;
      if (monitorRunMatch) return monitorRunDetail(store, url, decodeURIComponent(monitorRunMatch[1]));
      if (request.method === "GET" && url.pathname === "/api/runs") return json(runPage(await store.runs(scopeFrom(url), runQueryOptions(url, pageSize))));
      if (request.method === "GET" && url.pathname === "/api/findings") return json(findingPage(await store.findings(scopeFrom(url), findingQueryOptions(url, pageSize))));
      if (request.method === "GET" && url.pathname.startsWith("/api/runs/")) {
        const suffix = decodeURIComponent(url.pathname.slice("/api/runs/".length));
        const scope = requireFullScope(scopeFrom(url));
        const viewMatch = suffix.match(/^([^/]+)\/views\/([^/]+)$/u);
        if (viewMatch) {
          const view = await store.view(scope, viewMatch[1], viewMatch[2]);
          return view ? json({ ok: true, view, valuesRedacted: true }) : json({ ok: false, error: { code: "view_not_found" }, valuesRedacted: true }, 404);
        }
        const run = await store.run(scope, suffix);
        return run ? json({ ok: true, run, valuesRedacted: true }) : json({ ok: false, error: { code: "run_not_found" }, valuesRedacted: true }, 404);
      }
      return json({ ok: false, error: { code: "not_found" }, valuesRedacted: true }, 404);
    } catch (error) {
      return json({ ok: false, error: structuredError(error), valuesRedacted: true }, httpStatus(error));
    }
  };
  return { ingest, health, fetch };
}

async function monitorWorkspace(store: MonitorCentralStore, url: URL, pageSize: number): Promise<Record<string, unknown>> {
  const scope = scopeFrom(url);
  const status = optional(url, "status");
  const from = optionalDate(url, "from");
  const to = optionalDate(url, "to");
  const result = await store.monitorWorkspace(scope, { ...runQueryOptions(url, pageSize), status, from, to });
  const runtime = await monitorRuntimeProjection(store, scope);
  return {
    ok: true,
    query: { sentinelId: scope.sentinelId ?? null, node: scope.node ?? null, lane: scope.lane ?? null, status: status ?? null, from: from ?? null, to: to ?? null },
    health: runtime.health,
    freshness: runtime.freshness,
    cadence: runtime.cadence,
    summary: { totalRuns: result.totalRuns, statusCounts: result.statusCounts, findingCount: result.findingCount, latestSuccessAt: result.latestSuccessAt, latestFailureAt: result.latestFailureAt },
    runs: { items: result.items, nextCursor: result.nextCursor },
    selection: { defaultRunId: result.items[0]?.runId ?? null },
    valuesRedacted: true,
  };
}

async function monitorRuntimeProjection(store: MonitorCentralStore, scope: MonitorScope): Promise<Record<string, Record<string, unknown>>> {
  if (!scope.sentinelId || !scope.node || !scope.lane) return unavailableRuntime("full_scope_required");
  const metadata = await store.runtimeMetadata(scope as Required<MonitorScope>);
  const values = new Map(metadata.map((item) => [item.key, item]));
  const health = projectedRuntimeValue(values, ["monitor.health", "scheduler.health"]);
  const freshness = projectedRuntimeValue(values, ["monitor.freshness", "scheduler.freshness"]);
  const cadence = projectedRuntimeValue(values, ["monitor.cadence", "scheduler.cadence"]);
  return {
    health: health ?? { state: "degraded", reason: "runtime_metadata_unavailable" },
    freshness: freshness ?? { state: "unavailable", reason: "runtime_metadata_unavailable" },
    cadence: cadence ?? { state: "unavailable", reason: "runtime_metadata_unavailable" },
  };
}

function projectedRuntimeValue(values: ReadonlyMap<string, MonitorRuntimeMetadata>, keys: readonly string[]): Record<string, unknown> | null {
  for (const key of keys) {
    const item = values.get(key);
    if (item) return { ...recordOrEmpty(item.value), sourceKey: item.key, updatedAt: item.updatedAt };
  }
  return null;
}

function unavailableRuntime(reason: string): Record<string, Record<string, unknown>> {
  return { health: { state: "degraded", reason }, freshness: { state: "unavailable", reason }, cadence: { state: "unavailable", reason } };
}

async function monitorRunDetail(store: MonitorCentralStore, url: URL, runId: string): Promise<Response> {
  const scope = requireFullScope(scopeFrom(url));
  const run = await store.run(scope, runId);
  if (!run) return json({ ok: false, error: { code: "run_not_found" }, valuesRedacted: true }, 404);
  const payload = recordOrEmpty(run.payload);
  return json({ ok: true, run: { sentinelId: run.sentinelId, node: run.node, lane: run.lane, runId: run.runId, updatedAt: run.updatedAt, status: run.status, payloadHash: run.payloadHash }, timeline: arrayOrEmpty(run.timeline).map((event, index) => ({ id: objectId(event, `event-${index}`), event })), findings: arrayOrEmpty(run.findings).map((finding, index) => ({ id: objectId(finding, `finding-${index}`), finding })), diagnostics: recordOrEmpty(payload.diagnostics), artifacts: arrayOrEmpty(run.artifactLocators).map((artifact, index) => ({ id: `artifact-${index}`, ...recordOrEmpty(artifact) })), valuesRedacted: true });
}

export function createPostgresMonitorCentralStore(databaseUrl: string, options: PostgresMonitorCentralStoreOptions): MonitorCentralStore {
  const sql = postgres(databaseUrl, { max: requirePositiveInteger(options.poolMax, "monitor_central_pg_pool_max_missing"), idle_timeout: requirePositiveInteger(options.idleTimeoutSeconds, "monitor_central_pg_idle_timeout_missing") });
  return {
    async close() { await sql.end({ timeout: 0 }); },
    async migrate() {
      for (const statement of MONITOR_CENTRAL_MIGRATIONS) await sql.unsafe(statement);
      await sql`insert into monitor.schema_migrations (version, applied_at) values (${MONITOR_CENTRAL_SCHEMA_VERSION}, now()) on conflict (version) do nothing`;
    },
    async ping() { await sql`select 1`; },
    async schemaVersion() {
      const rows = await sql<{ version: string }[]>`select version from monitor.schema_migrations order by applied_at desc limit 1`;
      return rows[0]?.version ?? null;
    },
    async capability() {
      const rows = await sql<{ can_ingest: boolean; can_query: boolean }[]>`
        select
          has_table_privilege(current_user, 'monitor.runs', 'insert') as can_ingest,
          has_table_privilege(current_user, 'monitor.runs', 'select') as can_query`;
      return { ingest: rows[0]?.can_ingest === true, query: rows[0]?.can_query === true };
    },
    async ingest(input) {
      return sql.begin((transaction) => writePostgresIngest(transaction, input));
    },
    async importSource(manifest, inputs, runtimeMetadata = []) {
      return sql.begin(async (transaction) => {
        const claimed = await transaction<{ manifest_id: string }[]>`
          insert into monitor.import_manifests (manifest_id, source_fingerprint, row_count, imported_at)
          values (${manifest.manifestId}, ${manifest.sourceFingerprint}, ${manifest.rowCount}, now())
          on conflict (manifest_id) do nothing returning manifest_id`;
        if (!claimed[0]) {
          const existing = await transaction<{ source_fingerprint: string; row_count: string | number }[]>`
            select source_fingerprint, row_count from monitor.import_manifests where manifest_id = ${manifest.manifestId}`;
          if (existing[0].source_fingerprint !== manifest.sourceFingerprint || Number(existing[0].row_count) !== manifest.rowCount) {
            throw Object.assign(new Error("monitor import manifest conflict"), { code: "monitor_import_manifest_conflict" });
          }
          return { disposition: "idempotent" as const, runs: inputs.map(() => ({ disposition: "idempotent" as const })) };
        }
        const runs = [] as { disposition: "inserted" | "idempotent" }[];
        for (const input of inputs) runs.push(await writePostgresIngest(transaction, input));
        for (const item of runtimeMetadata) {
          await transaction`
            insert into monitor.runners (sentinel_id, node, lane, updated_at)
            values (${item.sentinelId}, ${item.node}, ${item.lane}, ${item.updatedAt})
            on conflict (sentinel_id, node, lane) do update set updated_at = greatest(monitor.runners.updated_at, excluded.updated_at)`;
          await transaction`
          insert into monitor.runtime_metadata (sentinel_id, node, lane, key, value, updated_at)
          values (${item.sentinelId}, ${item.node}, ${item.lane}, ${item.key}, ${JSON.stringify(item.value)}::jsonb, ${item.updatedAt})
          on conflict (sentinel_id, node, lane, key) do update set value = excluded.value, updated_at = excluded.updated_at`;
        }
        return { disposition: "inserted" as const, runs };
      });
    },
    async runtimeMetadata(scope) {
      const rows = await sql<({ key: string; value: unknown; updated_at: string })[]>`select key, value, updated_at from monitor.runtime_metadata where sentinel_id = ${scope.sentinelId} and node = ${scope.node} and lane = ${scope.lane} order by key`;
      return rows.map((item) => ({ ...scope, key: item.key, value: item.value, updatedAt: new Date(item.updated_at).toISOString() }));
    },
    async updateArtifactAvailability(scope, runId, locatorIndex, reachable) {
      await sql`
        update monitor.artifact_locators
        set reachable = ${reachable}
        where sentinel_id = ${scope.sentinelId} and node = ${scope.node} and lane = ${scope.lane} and run_id = ${runId} and locator_index = ${locatorIndex}`;
    },
    async overview(scope) {
      const rows = await queryRuns(sql, scope, { limit: 1, cursor: null });
      return { scope: publicScope(scope), runCount: await countRuns(sql, scope), latest: rows[0] ?? null };
    },
    async monitorWorkspace(scope, options) { return queryMonitorWorkspace(sql, scope, options); },
    async runs(scope, options) { return queryRuns(sql, scope, options); },
    async run(scope, runId) {
      const where = identityWhere(scope, runId);
      const rows = await sql.unsafe(`select r.sentinel_id, r.node, r.lane, r.run_id, r.updated_at, r.status, r.payload_hash, p.payload from monitor.runs r join monitor.run_payloads p using (sentinel_id, node, lane, run_id) where ${where.text} limit 1`, where.values);
      const row = rows[0] as Record<string, unknown> | undefined;
      if (!row) return null;
      const identity = rowIdentity(row);
      const [findings, locators, timeline] = await Promise.all([
        sql.unsafe(`select finding from monitor.findings where ${identity.text} order by finding_index`, identity.values),
        sql.unsafe(`select owner_node, owner_lane, owner_pvc, state_dir, relative_path, sha256, size_bytes, kind, reachable from monitor.artifact_locators where ${identity.text} order by locator_index`, identity.values),
        sql.unsafe(`select event from monitor.timeline_events where ${identity.text} order by event_index`, identity.values),
      ]);
      return { ...runRow(row), payload: row.payload, findings: findings.map((item) => item.finding), artifactLocators: locators.map(locatorRow), timeline: timeline.map((item) => item.event) };
    },
    async view(scope, runId, view) {
      const run = await this.run(scope, runId);
      if (!run) return null;
      const views = record(run.payload.views);
      const value = views[view];
      return value === undefined ? null : { runId, name: view, value };
    },
    async findings(scope, options) {
      const where = scopeWhere(scope);
      const values: unknown[] = [...where.values];
      const cursor = options.cursor ? (() => { values.push(options.cursor.updatedAt, options.cursor.runId, options.cursor.findingIndex); return `and (r.updated_at, r.run_id, f.finding_index) < ($${values.length - 2}, $${values.length - 1}, $${values.length})`; })() : "";
      values.push(options.limit);
      const rows = await sql.unsafe(`select f.finding, f.finding_index, r.sentinel_id, r.node, r.lane, r.run_id, r.updated_at, r.status, r.payload_hash from monitor.findings f join monitor.runs r using (sentinel_id, node, lane, run_id) where ${where.text} ${cursor} order by r.updated_at desc, r.run_id desc, f.finding_index desc limit $${values.length}`, values);
      return rows.map(mapPostgresFindingRow);
    },
  };
}

async function writePostgresIngest(transaction: postgres.TransactionSql, input: NormalizedMonitorCentralIngest): Promise<{ disposition: "inserted" | "idempotent" }> {
        await transaction`
          insert into monitor.runners (sentinel_id, node, lane, updated_at)
          values (${input.sentinelId}, ${input.node}, ${input.lane}, ${input.updatedAt})
          on conflict (sentinel_id, node, lane) do update set updated_at = greatest(monitor.runners.updated_at, excluded.updated_at)`;
        const inserted = await transaction<{ payload_hash: string }[]>`
          insert into monitor.runs (sentinel_id, node, lane, run_id, updated_at, status, payload_hash)
          values (${input.sentinelId}, ${input.node}, ${input.lane}, ${input.runId}, ${input.updatedAt}, ${input.status}, ${input.payloadHash})
          on conflict (sentinel_id, node, lane, run_id) do nothing
          returning payload_hash`;
        if (!inserted[0]) {
          const existing = await transaction<{ payload_hash: string }[]>`
            select payload_hash from monitor.runs
            where sentinel_id = ${input.sentinelId} and node = ${input.node} and lane = ${input.lane} and run_id = ${input.runId}`;
          if (existing[0]?.payload_hash === input.payloadHash) {
            await updatePostgresArtifactAvailability(transaction, input);
            return { disposition: "idempotent" as const };
          }
          throw conflict(input);
        }
        await transaction`
          insert into monitor.run_payloads (sentinel_id, node, lane, run_id, payload_hash, payload)
          values (${input.sentinelId}, ${input.node}, ${input.lane}, ${input.runId}, ${input.payloadHash}, ${JSON.stringify(input.payload)}::jsonb)`;
        for (const [index, finding] of input.findings.entries()) await transaction`
          insert into monitor.findings (sentinel_id, node, lane, run_id, finding_index, finding)
          values (${input.sentinelId}, ${input.node}, ${input.lane}, ${input.runId}, ${index}, ${JSON.stringify(finding)}::jsonb)`;
        for (const [index, locator] of input.artifactLocators.entries()) await transaction`
          insert into monitor.artifact_locators (sentinel_id, node, lane, run_id, locator_index, owner_node, owner_lane, owner_pvc, state_dir, relative_path, sha256, size_bytes, kind, reachable)
          values (${input.sentinelId}, ${input.node}, ${input.lane}, ${input.runId}, ${index}, ${locator.ownerNode}, ${locator.ownerLane}, ${locator.ownerPvc}, ${locator.stateDir}, ${locator.relativePath}, ${locator.sha256}, ${locator.sizeBytes}, ${locator.kind}, ${locator.reachable})`;
        for (const [index, event] of input.timeline.entries()) await transaction`
          insert into monitor.timeline_events (sentinel_id, node, lane, run_id, event_index, event)
          values (${input.sentinelId}, ${input.node}, ${input.lane}, ${input.runId}, ${index}, ${JSON.stringify(event)}::jsonb)`;
  return { disposition: "inserted" as const };
}

export const MONITOR_CENTRAL_MIGRATIONS = [
  "create schema if not exists monitor",
  "create table if not exists monitor.schema_migrations (version text primary key, applied_at timestamptz not null)",
  "create table if not exists monitor.runners (sentinel_id text not null, node text not null, lane text not null, updated_at timestamptz not null, primary key (sentinel_id, node, lane))",
  "create table if not exists monitor.runs (sentinel_id text not null, node text not null, lane text not null, run_id text not null, updated_at timestamptz not null, status text not null, payload_hash text not null, primary key (sentinel_id, node, lane, run_id), foreign key (sentinel_id, node, lane) references monitor.runners (sentinel_id, node, lane))",
  "create index if not exists monitor_runs_latest_idx on monitor.runs (updated_at desc, run_id desc)",
  "create table if not exists monitor.run_payloads (sentinel_id text not null, node text not null, lane text not null, run_id text not null, payload_hash text not null, payload jsonb not null, primary key (sentinel_id, node, lane, run_id), foreign key (sentinel_id, node, lane, run_id) references monitor.runs on delete cascade)",
  "create table if not exists monitor.findings (sentinel_id text not null, node text not null, lane text not null, run_id text not null, finding_index integer not null, finding jsonb not null, primary key (sentinel_id, node, lane, run_id, finding_index), foreign key (sentinel_id, node, lane, run_id) references monitor.runs on delete cascade)",
  "create table if not exists monitor.artifact_locators (sentinel_id text not null, node text not null, lane text not null, run_id text not null, locator_index integer not null, owner_node text not null, owner_lane text not null, owner_pvc text not null, state_dir text not null, relative_path text not null, sha256 text not null, size_bytes bigint not null, kind text not null, reachable boolean not null, primary key (sentinel_id, node, lane, run_id, locator_index), foreign key (sentinel_id, node, lane, run_id) references monitor.runs on delete cascade)",
  "create table if not exists monitor.timeline_events (sentinel_id text not null, node text not null, lane text not null, run_id text not null, event_index integer not null, event jsonb not null, primary key (sentinel_id, node, lane, run_id, event_index), foreign key (sentinel_id, node, lane, run_id) references monitor.runs on delete cascade)",
  "create table if not exists monitor.runtime_metadata (sentinel_id text not null, node text not null, lane text not null, key text not null, value jsonb not null, updated_at timestamptz not null, primary key (sentinel_id, node, lane, key), foreign key (sentinel_id, node, lane) references monitor.runners (sentinel_id, node, lane))",
  "create table if not exists monitor.import_manifests (manifest_id text primary key, source_fingerprint text not null, row_count bigint not null, imported_at timestamptz not null)",
];

export function createInMemoryMonitorCentralStore(): MonitorCentralStore {
  const records = new Map<string, NormalizedMonitorCentralIngest>();
  const manifests = new Map<string, MonitorImportManifest>();
  const metadata = new Map<string, MonitorRuntimeMetadata>();
  return {
    async close() {},
    async migrate() {},
    async ping() {},
    async schemaVersion() { return MONITOR_CENTRAL_SCHEMA_VERSION; },
    async capability() { return { ingest: true, query: true }; },
    async ingest(input) {
      const key = identityKey(input);
      const existing = records.get(key);
      if (existing) {
        if (existing.payloadHash !== input.payloadHash) throw conflict(input);
        records.set(key, { ...existing, artifactLocators: input.artifactLocators });
        return { disposition: "idempotent" };
      }
      records.set(key, structuredClone(input));
      return { disposition: "inserted" };
    },
    async importSource(manifest, inputs, runtimeMetadata = []) {
      const previous = manifests.get(manifest.manifestId);
      if (previous) {
        if (previous.sourceFingerprint !== manifest.sourceFingerprint || previous.rowCount !== manifest.rowCount) throw Object.assign(new Error("monitor import manifest conflict"), { code: "monitor_import_manifest_conflict" });
        return { disposition: "idempotent", runs: inputs.map(() => ({ disposition: "idempotent" as const })) };
      }
      const staged = new Map(records);
      const runs: { disposition: "inserted" | "idempotent" }[] = [];
      for (const input of inputs) {
        const existing = staged.get(identityKey(input));
        if (existing && existing.payloadHash !== input.payloadHash) throw conflict(input);
        if (existing) runs.push({ disposition: "idempotent" });
        else { staged.set(identityKey(input), structuredClone(input)); runs.push({ disposition: "inserted" }); }
      }
      records.clear();
      for (const [key, value] of staged) records.set(key, value);
      for (const item of runtimeMetadata) metadata.set(`${item.sentinelId}/${item.node}/${item.lane}/${item.key}`, structuredClone(item));
      manifests.set(manifest.manifestId, { ...manifest });
      return { disposition: "inserted", runs };
    },
    async runtimeMetadata(scope) { return [...metadata.values()].filter((item) => item.sentinelId === scope.sentinelId && item.node === scope.node && item.lane === scope.lane).sort((left, right) => left.key.localeCompare(right.key)).map(structuredClone); },
    async updateArtifactAvailability(scope, runId, locatorIndex, reachable) {
      const key = identityKey({ ...scope, runId });
      const existing = records.get(key);
      if (!existing?.artifactLocators[locatorIndex]) return;
      const artifactLocators = existing.artifactLocators.map((locator, index) => index === locatorIndex ? { ...locator, reachable } : locator);
      records.set(key, { ...existing, artifactLocators });
    },
    async overview(scope) {
      const runs = await this.runs(scope, { limit: 1, cursor: null });
      return { scope: publicScope(scope), runCount: [...records.values()].filter((item) => matches(scope, item)).length, latest: runs[0] ?? null };
    },
    async monitorWorkspace(scope, options) {
      const filteredRecords = [...records.values()].filter((item) => matches(scope, item) && monitorWorkspaceMatches(runFrom(item), options));
      const all = sortRuns(filteredRecords.map(runFrom));
      const findingCounts = new Map(filteredRecords.map((item) => [identityKey(item), item.findings.length]));
      const candidates = all.filter((run) => afterRunCursor(run, options.cursor)).slice(0, options.limit + 1);
      const hasMore = candidates.length > options.limit;
      const items = candidates.slice(0, options.limit).map((run) => ({ ...run, findingCount: findingCounts.get(identityKey(run)) ?? 0 }));
      const last = items.at(-1);
      return { items, nextCursor: hasMore && last ? cursor(last) : null, totalRuns: all.length, findingCount: filteredRecords.reduce((total, item) => total + item.findings.length, 0), statusCounts: countBy(all, (run) => run.status), latestSuccessAt: all.find((run) => run.status === "succeeded")?.updatedAt ?? null, latestFailureAt: all.find((run) => monitorRunFailed(run.status))?.updatedAt ?? null };
    },
    async runs(scope, options) { return sortRuns([...records.values()].filter((item) => matches(scope, item)).map(runFrom)).filter((run) => afterRunCursor(run, options.cursor)).slice(0, options.limit); },
    async run(scope, runId) {
      const value = records.get(identityKey({ ...scope, runId }));
      return value ? { ...runFrom(value), payload: value.payload, findings: value.findings, artifactLocators: value.artifactLocators, timeline: value.timeline } : null;
    },
    async view(scope, runId, view) {
      const detail = await this.run(scope, runId);
      const views = detail?.payload && typeof detail.payload === "object" ? (detail.payload as Record<string, unknown>).views : null;
      const value = views && typeof views === "object" ? (views as Record<string, unknown>)[view] : undefined;
      return value === undefined ? null : { runId, name: view, value };
    },
    async findings(scope, options) {
      return sortRuns([...records.values()].filter((item) => matches(scope, item)).map(runFrom)).flatMap((run) => {
        const source = records.get(identityKey(run))!;
        return source.findings.map((finding, findingIndex) => ({ ...run, findingIndex, finding }));
      }).sort(compareFindings).filter((finding) => afterFindingCursor(finding, options.cursor)).slice(0, options.limit);
    },
  };
}

function requireDatabaseUrl(databaseUrl: string | null | undefined): string { const value = databaseUrl ?? process.env.DATABASE_URL; if (!value) throw new MonitorCentralConfigurationError(); return value; }
function requirePostgresOptions(value: PostgresMonitorCentralStoreOptions | undefined): PostgresMonitorCentralStoreOptions { if (!value) throw Object.assign(new Error("Monitor central PostgreSQL pool configuration must be injected"), { code: "monitor_central_pg_options_missing" }); return value; }
function requirePositiveInteger(value: number | undefined, code: string): number { if (!Number.isSafeInteger(value) || value < 1) throw Object.assign(new Error(`${code} must be a positive integer`), { code }); return value; }
export function normalizeMonitorCentralIngest(input: MonitorCentralIngest): NormalizedMonitorCentralIngest {
  for (const key of ["sentinelId", "node", "lane", "runId"] as const) if (!input[key]) throw invalid(`missing required ingest field: ${key}`);
  const normalized = { ...input, updatedAt: input.updatedAt ?? new Date().toISOString(), status: input.status ?? "unknown", findings: input.findings ?? [], artifactLocators: (input.artifactLocators ?? []).map(normalizeLocator), timeline: input.timeline ?? [] };
  return { ...normalized, payloadHash: `sha256:${createHash("sha256").update(monitorCentralStableJson({ status: normalized.status, payload: normalized.payload, findings: normalized.findings, artifactLocators: normalized.artifactLocators.map(immutableLocator), timeline: normalized.timeline })).digest("hex")}` };
}
function immutableLocator(locator: MonitorArtifactLocator): Omit<MonitorArtifactLocator, "reachable"> { const { reachable: _reachable, ...immutable } = locator; return immutable; }
function normalizeLocator(value: MonitorArtifactLocator): MonitorArtifactLocator {
  for (const key of ["ownerNode", "ownerLane", "ownerPvc", "stateDir", "relativePath", "sha256", "kind"] as const) if (!value[key]) throw invalid(`artifact locator must include ${key}`);
  if (!Number.isSafeInteger(value.sizeBytes) || value.sizeBytes < 0) throw invalid("artifact locator sizeBytes must be a non-negative integer");
  if (typeof value.reachable !== "boolean") throw invalid("artifact locator reachable must be boolean");
  return { ...value };
}
async function requestRecord(request: Request): Promise<Record<string, unknown>> { const value = await request.json(); if (!value || typeof value !== "object" || Array.isArray(value)) throw invalid("ingest request body must be an object"); return value as Record<string, unknown>; }
function scopeFrom(url: URL): MonitorScope { return { sentinelId: optional(url, "sentinelId"), node: optional(url, "node"), lane: optional(url, "lane") }; }
function requireFullScope(scope: MonitorScope): Required<MonitorScope> { if (!scope.sentinelId || !scope.node || !scope.lane) throw Object.assign(invalid("run detail requires sentinelId, node, and lane"), { code: "scope_required" }); return scope as Required<MonitorScope>; }
function optional(url: URL, name: string): string | undefined { return url.searchParams.get(name) || undefined; }
function optionalDate(url: URL, name: string): string | undefined { const value = optional(url, name); if (!value) return undefined; const timestamp = Date.parse(value); if (!Number.isFinite(timestamp)) throw invalid(`${name} must be an ISO timestamp`); return new Date(timestamp).toISOString(); }
function boundedLimit(value: string | null, pageSize: number): number { const parsed = Number(value ?? pageSize); return Number.isInteger(parsed) && parsed > 0 ? Math.min(parsed, pageSize) : pageSize; }
function runQueryOptions(url: URL, pageSize: number): RunQueryOptions { return { limit: boundedLimit(url.searchParams.get("limit"), pageSize), cursor: parseRunCursor(url.searchParams.get("cursor")) }; }
function findingQueryOptions(url: URL, pageSize: number): FindingQueryOptions { return { limit: boundedLimit(url.searchParams.get("limit"), pageSize), cursor: parseFindingCursor(url.searchParams.get("cursor")) }; }
function parseRunCursor(value: string | null): RunCursor | null { return parseCursor(value, false) as RunCursor | null; }
function parseFindingCursor(value: string | null): FindingCursor | null { return parseCursor(value, true) as FindingCursor | null; }
function parseCursor(value: string | null, finding: boolean): RunCursor | FindingCursor | null { if (!value) return null; try { const decoded = JSON.parse(Buffer.from(value, "base64url").toString("utf8")); if (typeof decoded.updatedAt !== "string" || typeof decoded.runId !== "string" || (finding && !Number.isInteger(decoded.findingIndex))) throw new Error("invalid cursor"); return decoded; } catch { throw invalid("invalid cursor"); } }
function runPage(items: readonly MonitorRun[]): Record<string, unknown> { const last = items.at(-1); return { ok: true, items, nextCursor: last ? cursor(last) : null, valuesRedacted: true }; }
function findingPage(items: readonly Record<string, unknown>[]): Record<string, unknown> { const last = items.at(-1); return { ok: true, items, nextCursor: last ? cursor({ updatedAt: last.updatedAt, runId: last.runId, findingIndex: last.findingIndex }) : null, valuesRedacted: true }; }
function cursor(value: unknown): string { return Buffer.from(JSON.stringify(value)).toString("base64url"); }
function countBy<T>(items: readonly T[], key: (item: T) => string): Record<string, number> { const counts: Record<string, number> = {}; for (const item of items) counts[key(item)] = (counts[key(item)] ?? 0) + 1; return counts; }
function recordOrEmpty(value: unknown): Record<string, unknown> { return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : {}; }
function arrayOrEmpty(value: unknown): readonly unknown[] { return Array.isArray(value) ? value : []; }
function objectId(value: unknown, fallback: string): string { const record = recordOrEmpty(value); return String(record.id ?? record.errorId ?? fallback); }
function dateOrNull(value: unknown): string | null { return value ? new Date(String(value)).toISOString() : null; }
function json(body: Record<string, unknown>, status = 200): Response { return Response.json(body, { status }); }
function httpStatus(error: unknown): number { return (error as { code?: string })?.code === "payload_hash_conflict" ? 409 : error instanceof MonitorCentralConfigurationError ? 503 : 400; }
export function structuredMonitorCentralError(error: unknown): Record<string, unknown> { return error instanceof MonitorCentralConfigurationError ? error.toJSON().error as Record<string, unknown> : { code: (error as { code?: string })?.code ?? "invalid_request", message: errorMessage(error) }; }
function structuredError(error: unknown): Record<string, unknown> { return structuredMonitorCentralError(error); }
function invalid(message: string): Error & { code: string } { return Object.assign(new Error(message), { code: "invalid_request" }); }
function errorMessage(error: unknown): string { return error instanceof Error ? error.message.replace(/postgres(?:ql)?:\/\/[^\s]+/giu, "postgres://<redacted>") : "unknown error"; }
function identityOf(value: MonitorScope & { readonly runId: string }): Record<string, unknown> { return { sentinelId: value.sentinelId, node: value.node, lane: value.lane, runId: value.runId }; }
function identityKey(value: MonitorScope & { readonly runId: string }): string { return [value.sentinelId, value.node, value.lane, value.runId].join("\u0000"); }
function conflict(value: MonitorCentralIngest): Error & { code: string } { return Object.assign(new Error("ingest identity already has a different terminal envelope"), { code: "payload_hash_conflict", identity: identityOf(value) }); }
function publicScope(scope: MonitorScope): Record<string, unknown> { return { sentinelId: scope.sentinelId ?? null, node: scope.node ?? null, lane: scope.lane ?? null }; }
function matches(scope: MonitorScope, value: MonitorScope): boolean { return (!scope.sentinelId || scope.sentinelId === value.sentinelId) && (!scope.node || scope.node === value.node) && (!scope.lane || scope.lane === value.lane); }
function runFrom(value: NormalizedMonitorCentralIngest): MonitorRun { return { sentinelId: value.sentinelId, node: value.node, lane: value.lane, runId: value.runId, updatedAt: value.updatedAt, status: value.status, payloadHash: value.payloadHash }; }
function sortRuns(runs: readonly MonitorRun[]): MonitorRun[] { return [...runs].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt) || right.runId.localeCompare(left.runId)); }
function afterRunCursor(run: MonitorRun, cursorValue: RunCursor | null): boolean { return !cursorValue || run.updatedAt < cursorValue.updatedAt || (run.updatedAt === cursorValue.updatedAt && run.runId < cursorValue.runId); }
function monitorWorkspaceMatches(run: MonitorRun, options: MonitorWorkspaceQueryOptions): boolean { return (!options.status || run.status === options.status) && (!options.from || run.updatedAt >= options.from) && (!options.to || run.updatedAt <= options.to); }
function monitorRunFailed(status: string): boolean { return status === "failed"; }
function compareFindings(left: Record<string, unknown>, right: Record<string, unknown>): number { return String(right.updatedAt).localeCompare(String(left.updatedAt)) || String(right.runId).localeCompare(String(left.runId)) || Number(right.findingIndex) - Number(left.findingIndex); }
function afterFindingCursor(finding: Record<string, unknown>, cursorValue: FindingCursor | null): boolean { if (!cursorValue) return true; return String(finding.updatedAt) < cursorValue.updatedAt || (finding.updatedAt === cursorValue.updatedAt && (String(finding.runId) < cursorValue.runId || (finding.runId === cursorValue.runId && Number(finding.findingIndex) < cursorValue.findingIndex))); }
export function monitorCentralStableJson(value: unknown): string { if (value === undefined) return "null"; if (Array.isArray(value)) return `[${value.map(monitorCentralStableJson).join(",")}]`; if (value && typeof value === "object") return `{${Object.entries(value as Record<string, unknown>).filter(([, item]) => item !== undefined).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${monitorCentralStableJson(item)}`).join(",")}}`; const json = JSON.stringify(value); return json === undefined ? "null" : json; }
function scopeWhere(scope: MonitorScope): { readonly text: string; readonly values: readonly string[] } { const entries = Object.entries({ sentinel_id: scope.sentinelId, node: scope.node, lane: scope.lane }).filter(([, value]) => value); return { text: entries.length ? entries.map(([key], index) => `r.${key} = $${index + 1}`).join(" and ") : "true", values: entries.map(([, value]) => String(value)) }; }
function identityWhere(scope: Required<MonitorScope>, runId: string): { readonly text: string; readonly values: readonly string[] } { return { text: "r.sentinel_id = $1 and r.node = $2 and r.lane = $3 and r.run_id = $4", values: [scope.sentinelId, scope.node, scope.lane, runId] }; }
async function queryRuns(sql: postgres.Sql, scope: MonitorScope, options: RunQueryOptions): Promise<MonitorRun[]> { const where = scopeWhere(scope); const values: unknown[] = [...where.values]; let cursorClause = ""; if (options.cursor) { values.push(options.cursor.updatedAt, options.cursor.runId); cursorClause = `and (r.updated_at, r.run_id) < ($${values.length - 1}, $${values.length})`; } values.push(options.limit); const rows = await sql.unsafe(`select r.sentinel_id, r.node, r.lane, r.run_id, r.updated_at, r.status, r.payload_hash from monitor.runs r where ${where.text} ${cursorClause} order by r.updated_at desc, r.run_id desc limit $${values.length}`, values); return rows.map(runRow); }
async function queryMonitorWorkspace(sql: postgres.Sql, scope: MonitorScope, options: MonitorWorkspaceQueryOptions): Promise<MonitorWorkspaceQueryResult> {
  const where = scopeWhere(scope);
  const values: unknown[] = [...where.values];
  const filters: string[] = [where.text];
  if (options.status) { values.push(options.status); filters.push(`r.status = $${values.length}`); }
  if (options.from) { values.push(options.from); filters.push(`r.updated_at >= $${values.length}`); }
  if (options.to) { values.push(options.to); filters.push(`r.updated_at <= $${values.length}`); }
  const baseValues = [...values];
  let cursorClause = "";
  if (options.cursor) { values.push(options.cursor.updatedAt, options.cursor.runId); cursorClause = `and (r.updated_at, r.run_id) < ($${values.length - 1}, $${values.length})`; }
  values.push(options.limit + 1);
  const predicate = filters.join(" and ");
  const [pageRows, summaryRows, statusRows] = await Promise.all([
    sql.unsafe(`select r.sentinel_id, r.node, r.lane, r.run_id, r.updated_at, r.status, r.payload_hash, count(f.finding_index)::int as finding_count from monitor.runs r left join monitor.findings f using (sentinel_id, node, lane, run_id) where ${predicate} ${cursorClause} group by r.sentinel_id, r.node, r.lane, r.run_id, r.updated_at, r.status, r.payload_hash order by r.updated_at desc, r.run_id desc limit $${values.length}`, values),
    sql.unsafe(`select count(*)::int as total_runs, coalesce(sum(finding_count),0)::int as finding_count, max(updated_at) filter (where status = 'succeeded') as latest_success_at, max(updated_at) filter (where status = 'failed') as latest_failure_at from (select r.status, r.updated_at, count(f.finding_index)::int as finding_count from monitor.runs r left join monitor.findings f using (sentinel_id, node, lane, run_id) where ${predicate} group by r.sentinel_id, r.node, r.lane, r.run_id, r.status, r.updated_at) filtered`, baseValues),
    sql.unsafe(`select r.status, count(*)::int as status_count from monitor.runs r where ${predicate} group by r.status`, baseValues),
  ]);
  const hasMore = pageRows.length > options.limit;
  const items = pageRows.slice(0, options.limit).map((row) => ({ ...runRow(row), findingCount: Number(row.finding_count ?? 0) }));
  const summary = summaryRows[0] ?? {};
  const last = items.at(-1);
  return { items, nextCursor: hasMore && last ? cursor(last) : null, totalRuns: Number(summary.total_runs ?? 0), findingCount: Number(summary.finding_count ?? 0), statusCounts: Object.fromEntries(statusRows.map((row) => [String(row.status), Number(row.status_count)])), latestSuccessAt: dateOrNull(summary.latest_success_at), latestFailureAt: dateOrNull(summary.latest_failure_at) };
}
async function countRuns(sql: postgres.Sql, scope: MonitorScope): Promise<number> { const where = scopeWhere(scope); const rows = await sql.unsafe(`select count(*)::int as count from monitor.runs r where ${where.text}`, where.values); return Number(rows[0]?.count ?? 0); }
async function updatePostgresArtifactAvailability(transaction: postgres.TransactionSql, input: NormalizedMonitorCentralIngest): Promise<void> {
  for (const [index, locator] of input.artifactLocators.entries()) await transaction`
    update monitor.artifact_locators
    set reachable = ${locator.reachable}
    where sentinel_id = ${input.sentinelId} and node = ${input.node} and lane = ${input.lane} and run_id = ${input.runId} and locator_index = ${index}`;
}
function rowIdentity(row: Record<string, unknown>): { readonly text: string; readonly values: readonly string[] } { return { text: "sentinel_id = $1 and node = $2 and lane = $3 and run_id = $4", values: [String(row.sentinel_id), String(row.node), String(row.lane), String(row.run_id)] }; }
function runRow(row: Record<string, unknown>): MonitorRun { return { sentinelId: String(row.sentinel_id), node: String(row.node), lane: String(row.lane), runId: String(row.run_id), updatedAt: new Date(String(row.updated_at)).toISOString(), status: String(row.status), payloadHash: String(row.payload_hash) }; }
export function mapPostgresFindingRow(row: Record<string, unknown>): Record<string, unknown> { return { ...runRow(row), findingIndex: Number(row.finding_index), finding: row.finding }; }
function locatorRow(row: Record<string, unknown>): MonitorArtifactLocator { return { ownerNode: String(row.owner_node), ownerLane: String(row.owner_lane), ownerPvc: String(row.owner_pvc), stateDir: String(row.state_dir), relativePath: String(row.relative_path), sha256: String(row.sha256), sizeBytes: Number(row.size_bytes), kind: String(row.kind), reachable: row.reachable === true }; }
