import { createHash, randomBytes } from "node:crypto";
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, isAbsolute, join } from "node:path";
import type { UniDeskConfig } from "./config";
import { rootPath } from "./config";
import { startJob } from "./jobs";
import type { RenderedCliResult } from "./output";
import { pk01CaddyMergeManagedBlocksPython, renderCaddyManagedBlock, renderSimpleReverseProxyCaddySiteBlock } from "./pk01-caddy";
import { capture, compactCapture, parseJsonOutput, prepareFrpcSecret, shQuote } from "./platform-infra-public-service";
import { yamlBooleanField, yamlFieldLabel, yamlIntegerField } from "./platform-infra-ops-library";
import { fingerprintSecretValues, parseEnvFile, readEnvSourceFile, readTextFile, redactRepoPath, requiredEnvValue } from "./secrets";

const serviceName = "sub2api";
const fieldManager = "unidesk-platform-infra";
const manifestPath = rootPath("src", "components", "platform-infra", "sub2api", "sub2api.k8s.yaml");
const configPath = rootPath("config", "platform-infra", "sub2api.yaml");
const codexPoolConfigPath = rootPath("config", "platform-infra", "sub2api-codex-pool.yaml");
const sub2apiCaddyManagedMarker = "sub2api";
const requiredSecretKeys = ["POSTGRES_PASSWORD", "ADMIN_PASSWORD", "JWT_SECRET", "TOTP_ENCRYPTION_KEY"] as const;

type DatabaseMode = "bundled" | "external-pending" | "external-active";
type RedisMode = "bundled-persistent" | "local-ephemeral";

interface Sub2ApiConfig {
  version: number;
  kind: string;
  metadata: {
    id: string;
    owner: string;
    relatedIssues: number[];
  };
  defaults: Sub2ApiDefaults;
  image: {
    repository: string;
    tag: string;
    pullPolicy: "Always" | "IfNotPresent" | "Never";
  };
  dependencyImages: {
    postgres: string;
    redis: string;
  };
  security: {
    urlAllowlist: {
      enabled: boolean;
      allowInsecureHttp: boolean;
      allowPrivateHosts: boolean;
      upstreamHosts: string[];
    };
  };
  targets: Sub2ApiTargetConfig[];
  runtime: {
    database: ExternalDatabaseConfig;
    secrets: RuntimeSecretsConfig;
    redis: RuntimeRedisConfig;
    appData: {
      mode: "persistent-pvc" | "empty-dir";
    };
    sentinel: {
      mode: "singleton";
      enabledOnTargets: string[];
    };
  };
}

interface Sub2ApiDefaults {
  targetId: string;
  cleanup: {
    externalDbState: {
      postgresStatefulSetName: string;
      postgresServiceName: string;
      postgresPvcName: string;
      appDataPvcName: string;
    };
    redisPersistentState: {
      pvcName: string;
    };
    publicExposure: {
      deploymentName: string;
      configMapName: string;
      secretName: string;
    };
    egressProxy: {
      deploymentName: string;
      serviceName: string;
      secretName: string;
    };
  };
}

interface Sub2ApiTargetConfig {
  id: string;
  route: string;
  namespace: string;
  role: string;
  enabled: boolean;
  databaseMode: DatabaseMode;
  redisMode: RedisMode;
  appReplicas: number;
  redisReplicas: number;
  image: Partial<Sub2ApiConfig["image"]>;
  dependencyImages: Partial<Sub2ApiConfig["dependencyImages"]>;
  publicExposure: Sub2ApiPublicExposureConfig | null;
  egressProxy: Sub2ApiEgressProxyConfig | null;
}

interface Sub2ApiPublicExposureConfig {
  enabled: boolean;
  publicBaseUrl: string;
  dns: {
    hostname: string;
    expectedA: string;
    resolvers: string[];
  };
  frpc: {
    deploymentName: string;
    secretName: string;
    secretKey: string;
    image: string;
    serverAddr: string;
    serverPort: number;
    proxyName: string;
    remotePort: number;
    localIP: string;
    localPort: number;
    tokenSourceRef: string;
    tokenSourceKey: string;
  };
  pk01: {
    route: string;
    caddyBinaryPath: string;
    caddyDownloadUrl: string;
    caddyDownloadProxyUrl: string | null;
    caddyConfigPath: string;
    caddyServiceName: string;
    caddyStorageDir: string;
    caddyEmail: string;
    pikanodeRoot: string;
    pikanodeContainerName: string;
    pikanodeImage: string;
    pikanodeHttpHostPort: number;
    responseHeaderTimeoutSeconds: number;
  };
}

interface Sub2ApiEgressProxyConfig {
  enabled: boolean;
  deploymentName: string;
  serviceName: string;
  secretName: string;
  secretKey: string;
  image: string;
  imagePullPolicy: "Always" | "IfNotPresent" | "Never";
  listenPort: number;
  sourceRef: string;
  sourceKey: string;
  sourceType: "subscription-url";
  preferredOutbound: "vless-reality" | "hysteria2";
  noProxy: string[];
  applyToSub2Api: boolean;
  applyToSentinel: boolean;
  healthProbeUrl: string;
}

interface ExternalDatabaseConfig {
  mode: "external";
  sourceRef: string;
  sourceKeys: {
    user: string;
    password: string;
    dbName: string;
  };
  secretName: string;
  passwordKey: string;
  host: string;
  port: number;
  user: string;
  dbName: string;
  sslMode: string;
  pendingAllowed: boolean;
}

interface RuntimeSecretsConfig {
  root: string;
  appSourceRef: string;
}

interface RuntimeRedisConfig {
  serviceName: string;
  persistence: boolean;
}

interface ExternalActiveSecretMaterial {
  sourceRef: string;
  sourcePath: string;
  appSourceRef: string;
  appSourcePath: string;
  action: "create" | "update" | "none";
  fingerprint: string;
  values: Record<typeof requiredSecretKeys[number], string>;
}

interface PublicExposureSecretMaterial {
  sourceRef: string;
  sourcePath: string;
  secretName: string;
  secretKey: string;
  fingerprint: string;
  frpcToml: string;
  valuesPrinted: false;
}

interface EgressProxySecretMaterial {
  sourceRef: string;
  sourcePath: string;
  secretName: string;
  secretKey: string;
  fingerprint: string;
  subscriptionBytes: number;
  selectedOutbound: string;
  configJson: string;
  proxyUrl: string;
  noProxy: string;
  valuesPrinted: false;
}

interface ManagedResourceCleanupPlan {
  externalDbState: {
    enabled: boolean;
    postgresStatefulSetName: string;
    postgresServiceName: string;
    postgresPvcName: string;
    appDataPvcName: string;
  };
  redisPersistentState: {
    enabled: boolean;
    pvcName: string;
  };
  publicExposure: {
    enabled: boolean;
    deploymentName: string;
    configMapName: string;
    secretName: string;
  };
  egressProxy: {
    enabled: boolean;
    deploymentName: string;
    serviceName: string;
    secretName: string;
  };
  sentinel: {
    enabled: boolean;
    cronJobName: string;
    configMapName: string;
    credentialsSecretName: string;
    stateConfigMapName: string;
    serviceAccountName: string;
    roleName: string;
    roleBindingName: string;
  };
}

export function platformInfraHelp(): unknown {
  const target = sub2ApiHelpTargetSummary();
  return {
    command: "platform-infra sub2api|langbot|n8n|wechat-archive|observability ...",
    output: "json",
    usage: [
      "bun scripts/cli.ts platform-infra sub2api plan [--target G14|D601]",
      "bun scripts/cli.ts platform-infra sub2api apply [--target G14|D601] --dry-run",
      "bun scripts/cli.ts platform-infra sub2api apply [--target G14|D601] --confirm",
      "bun scripts/cli.ts platform-infra sub2api status [--target G14|D601] [--full|--raw]",
      "bun scripts/cli.ts platform-infra sub2api validate [--target G14|D601] [--full|--raw]",
      "bun scripts/cli.ts platform-infra sub2api codex-pool plan",
      "bun scripts/cli.ts platform-infra sub2api codex-pool sync --confirm",
      "bun scripts/cli.ts platform-infra sub2api codex-pool validate",
      "bun scripts/cli.ts platform-infra sub2api codex-pool trace --request-id <requestId>",
      "bun scripts/cli.ts platform-infra sub2api codex-pool sentinel-image status",
      "bun scripts/cli.ts platform-infra sub2api codex-pool sentinel-probe --account unidesk-codex-hy --confirm",
      "bun scripts/cli.ts platform-infra langbot plan [--target G14]",
      "bun scripts/cli.ts platform-infra langbot apply [--target G14] --confirm",
      "bun scripts/cli.ts platform-infra langbot status [--target G14] [--full|--raw]",
      "bun scripts/cli.ts platform-infra langbot logs [--target G14] [--component app|plugin-runtime|frpc|all]",
      "bun scripts/cli.ts platform-infra langbot bootstrap-api-key --confirm",
      "bun scripts/cli.ts platform-infra langbot query --path /api/v1/platform/bots",
      "bun scripts/cli.ts platform-infra n8n plan [--target G14]",
      "bun scripts/cli.ts platform-infra n8n apply [--target G14] --confirm",
      "bun scripts/cli.ts platform-infra n8n status [--target G14] [--full|--raw]",
      "bun scripts/cli.ts platform-infra n8n logs [--target G14] [--component app|frpc|all]",
      "bun scripts/cli.ts platform-infra n8n validate [--target G14] [--full|--raw]",
      "bun scripts/cli.ts platform-infra wechat-archive plan [--target G14]",
      "bun scripts/cli.ts platform-infra wechat-archive apply [--target G14] --confirm",
      "bun scripts/cli.ts platform-infra wechat-archive status [--target G14] [--full|--raw]",
      "bun scripts/cli.ts platform-infra wechat-archive validate [--target G14] [--full|--raw]",
      "bun scripts/cli.ts platform-infra wechat-archive pull --remote-path /UniDesk/WeChatArchive/...",
      "bun scripts/cli.ts platform-infra wechat-archive wcf-host-prepare --confirm",
      "bun scripts/cli.ts platform-infra wechat-archive wcf-host-start --confirm",
      "bun scripts/cli.ts platform-infra wechat-archive collector-image-build --confirm",
      "bun scripts/cli.ts platform-infra wechat-archive collector-apply --confirm",
      "bun scripts/cli.ts platform-infra wechat-archive collector-status --full",
      "bun scripts/cli.ts platform-infra observability plan --target D601",
      "bun scripts/cli.ts platform-infra observability apply --target D601 --dry-run",
      "bun scripts/cli.ts platform-infra observability apply --target D601 --confirm",
      "bun scripts/cli.ts platform-infra observability status --target D601",
      "bun scripts/cli.ts platform-infra observability validate --target D601",
      "bun scripts/cli.ts platform-infra observability trace --target D601 --trace-id <traceId> [--grep text] [--limit 40] [--full|--raw]",
      "bun scripts/cli.ts platform-infra observability search --target D601 --grep 'no rollout found' [--lookback-minutes 360] [--candidate-limit 80] [--limit 20]",
      "bun scripts/cli.ts platform-infra observability diagnose-code-agent --target D601 --business-trace-id <trc_...> [--full|--raw]",
    ],
    description: "Operate YAML-controlled platform-infra services such as Sub2API, LangBot, n8n, WeChat archive workflows and OpenTelemetry tracing. Public services use PK01 Caddy+FRP rather than Kubernetes Ingress, NodePort, or LoadBalancer.",
    target,
    codexPool: {
      usage: [
        "bun scripts/cli.ts platform-infra sub2api codex-pool plan",
        "bun scripts/cli.ts platform-infra sub2api codex-pool sync --confirm",
        "bun scripts/cli.ts platform-infra sub2api codex-pool validate",
        "bun scripts/cli.ts platform-infra sub2api codex-pool trace --request-id <requestId>",
        "bun scripts/cli.ts platform-infra sub2api codex-pool sentinel-image status",
      ],
      module: "scripts/src/platform-infra-sub2api-codex.ts",
    },
  };
}

function sub2ApiHelpTargetSummary(): Record<string, unknown> {
  const sub2api = readSub2ApiConfig();
  const target = resolveTarget(sub2api, sub2api.defaults.targetId);
  return {
    default: sub2api.defaults.targetId,
    namespace: target.namespace,
    service: serviceName,
    serviceDns: `${serviceName}.${target.namespace}.svc.cluster.local:8080`,
    exposure: target.publicExposure?.enabled === true ? "yaml-controlled-public-exposure" : "k3s-cluster-internal-only",
    resourceLimits: "unset-by-policy",
    versionConfigPath: configPath,
  };
}

export async function runPlatformInfraCommand(config: UniDeskConfig, args: string[]): Promise<Record<string, unknown> | RenderedCliResult> {
  const [target, action] = args;
  if (target === "langbot") {
    const { runLangBotCommand } = await import("./platform-infra-langbot");
    return await runLangBotCommand(config, args.slice(1));
  }
  if (target === "n8n") {
    const { runN8nCommand } = await import("./platform-infra-n8n");
    return await runN8nCommand(config, args.slice(1));
  }
  if (target === "wechat-archive") {
    const { runWechatArchiveCommand } = await import("./platform-infra-wechat-archive");
    return await runWechatArchiveCommand(config, args.slice(1));
  }
  if (target === "observability") {
    const { runPlatformObservabilityCommand } = await import("./platform-infra-observability");
    return await runPlatformObservabilityCommand(config, args.slice(1));
  }
  if (target !== "sub2api") return unsupported(args);
  if (action === "plan" || action === undefined) return plan(parseTargetOptions(args.slice(2)));
  if (action === "apply") return await apply(config, parseApplyOptions(args.slice(2)));
  if (action === "status") return await status(config, parseDisclosureOptions(args.slice(2)));
  if (action === "validate") return await validate(config, parseDisclosureOptions(args.slice(2)));
  if (action === "codex-pool") {
    const { runCodexPoolCommand } = await import("./platform-infra-sub2api-codex");
    return await runCodexPoolCommand(config, args.slice(2));
  }
  return unsupported(args);
}

interface ApplyOptions {
  targetId: string;
  dryRun: boolean;
  confirm: boolean;
  wait: boolean;
}

interface DisclosureOptions {
  targetId: string;
  full: boolean;
  raw: boolean;
}

interface TargetOptions {
  targetId: string;
}

interface PolicyCheck {
  name: string;
  ok: boolean;
  detail: string;
}

function unsupported(args: string[]): Record<string, unknown> {
  return {
    ok: false,
    error: "unsupported-platform-infra-command",
    args,
    help: platformInfraHelp(),
  };
}

function parseApplyOptions(args: string[]): ApplyOptions {
  const target = parseTargetOptions(args);
  validateOptions(args, new Set(["--dry-run", "--confirm", "--wait", "--target"]));
  if (args.includes("--dry-run") && args.includes("--confirm")) throw new Error("apply accepts only one of --dry-run or --confirm");
  return {
    targetId: target.targetId,
    dryRun: args.includes("--dry-run") || !args.includes("--confirm"),
    confirm: args.includes("--confirm"),
    wait: args.includes("--wait"),
  };
}

function parseDisclosureOptions(args: string[]): DisclosureOptions {
  const target = parseTargetOptions(args);
  validateOptions(args, new Set(["--full", "--raw", "--target"]));
  const raw = args.includes("--raw");
  return { targetId: target.targetId, full: raw || args.includes("--full"), raw };
}

function parseTargetOptions(args: string[]): TargetOptions {
  let targetId: string | null = null;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--target") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error("--target requires a value");
      targetId = value;
      index += 1;
    } else if (arg.startsWith("--target=")) {
      targetId = arg.slice("--target=".length);
    }
  }
  const resolvedTargetId = targetId ?? defaultSub2ApiTargetId();
  if (!/^[A-Za-z0-9._-]+$/u.test(resolvedTargetId)) throw new Error("--target must be a simple target id");
  return { targetId: resolvedTargetId };
}

function defaultSub2ApiTargetId(): string {
  return readSub2ApiConfig().defaults.targetId;
}

function validateOptions(args: string[], booleanOptions: Set<string>): void {
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--target") {
      index += 1;
      continue;
    }
    if (arg.startsWith("--target=") && booleanOptions.has("--target")) continue;
    if (booleanOptions.has(arg)) continue;
    throw new Error(`unsupported option: ${arg}`);
  }
}

function readSub2ApiConfig(): Sub2ApiConfig {
  const parsed = Bun.YAML.parse(readFileSync(configPath, "utf8")) as unknown;
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error(`${configPath} must contain a YAML object`);
  const root = parsed as Record<string, unknown>;
  const version = integerField(root, "version", "");
  if (version !== 1) throw new Error(`${configPath}.version must be 1`);
  const kind = stringField(root, "kind", "");
  if (kind !== "platform-infra-sub2api") throw new Error(`${configPath}.kind must be platform-infra-sub2api`);
  const metadata = objectField(root, "metadata", "");
  const relatedIssues = integerArrayField(metadata, "relatedIssues", "metadata");
  const defaults = parseDefaults(root);
  const image = (parsed as { image?: unknown }).image;
  if (typeof image !== "object" || image === null || Array.isArray(image)) throw new Error(`${configPath}.image must be an object`);
  const record = image as Record<string, unknown>;
  const repository = stringField(record, "repository", "image");
  const tag = stringField(record, "tag", "image");
  const pullPolicy = stringField(record, "pullPolicy", "image");
  if (pullPolicy !== "Always" && pullPolicy !== "IfNotPresent" && pullPolicy !== "Never") throw new Error(`${configPath}.image.pullPolicy must be Always, IfNotPresent, or Never`);
  if (!isImageRepository(repository)) throw new Error(`${configPath}.image.repository has an unsupported format`);
  if (!/^[A-Za-z0-9._-]+$/u.test(tag)) throw new Error(`${configPath}.image.tag has an unsupported format`);
  const dependencyImages = parseDependencyImages(root);
  const security = objectField(parsed as Record<string, unknown>, "security", "");
  const urlAllowlist = objectField(security, "urlAllowlist", "security");
  const enabled = booleanField(urlAllowlist, "enabled", "security.urlAllowlist");
  const allowInsecureHttp = booleanField(urlAllowlist, "allowInsecureHttp", "security.urlAllowlist");
  const allowPrivateHosts = booleanField(urlAllowlist, "allowPrivateHosts", "security.urlAllowlist");
  const upstreamHosts = stringArrayField(urlAllowlist, "upstreamHosts", "security.urlAllowlist");
  const targets = parseTargets(root, defaults.targetId);
  const runtime = parseRuntime(root);
  return {
    version,
    kind,
    metadata: {
      id: stringField(metadata, "id", "metadata"),
      owner: stringField(metadata, "owner", "metadata"),
      relatedIssues,
    },
    defaults,
    image: { repository, tag, pullPolicy },
    dependencyImages,
    security: {
      urlAllowlist: {
        enabled,
        allowInsecureHttp,
        allowPrivateHosts,
        upstreamHosts,
      },
    },
    targets,
    runtime,
  };
}

function parseDefaults(root: Record<string, unknown>): Sub2ApiDefaults {
  const defaults = objectField(root, "defaults", "");
  const targetId = stringField(defaults, "targetId", "defaults");
  if (!/^[A-Za-z0-9._-]+$/u.test(targetId)) throw new Error(`${configPath}.defaults.targetId must be a simple target id`);
  const cleanup = objectField(defaults, "cleanup", "defaults");
  const externalDbState = objectField(cleanup, "externalDbState", "defaults.cleanup");
  const redisPersistentState = objectField(cleanup, "redisPersistentState", "defaults.cleanup");
  const publicExposure = objectField(cleanup, "publicExposure", "defaults.cleanup");
  const egressProxy = objectField(cleanup, "egressProxy", "defaults.cleanup");
  const parsed: Sub2ApiDefaults = {
    targetId,
    cleanup: {
      externalDbState: {
        postgresStatefulSetName: stringField(externalDbState, "postgresStatefulSetName", "defaults.cleanup.externalDbState"),
        postgresServiceName: stringField(externalDbState, "postgresServiceName", "defaults.cleanup.externalDbState"),
        postgresPvcName: stringField(externalDbState, "postgresPvcName", "defaults.cleanup.externalDbState"),
        appDataPvcName: stringField(externalDbState, "appDataPvcName", "defaults.cleanup.externalDbState"),
      },
      redisPersistentState: {
        pvcName: stringField(redisPersistentState, "pvcName", "defaults.cleanup.redisPersistentState"),
      },
      publicExposure: {
        deploymentName: stringField(publicExposure, "deploymentName", "defaults.cleanup.publicExposure"),
        configMapName: stringField(publicExposure, "configMapName", "defaults.cleanup.publicExposure"),
        secretName: stringField(publicExposure, "secretName", "defaults.cleanup.publicExposure"),
      },
      egressProxy: {
        deploymentName: stringField(egressProxy, "deploymentName", "defaults.cleanup.egressProxy"),
        serviceName: stringField(egressProxy, "serviceName", "defaults.cleanup.egressProxy"),
        secretName: stringField(egressProxy, "secretName", "defaults.cleanup.egressProxy"),
      },
    },
  };
  const resourceNames = {
    ...parsed.cleanup.externalDbState,
    redisPersistentPvcName: parsed.cleanup.redisPersistentState.pvcName,
    publicExposureDeploymentName: parsed.cleanup.publicExposure.deploymentName,
    publicExposureConfigMapName: parsed.cleanup.publicExposure.configMapName,
    publicExposureSecretName: parsed.cleanup.publicExposure.secretName,
    egressProxyDeploymentName: parsed.cleanup.egressProxy.deploymentName,
    egressProxyServiceName: parsed.cleanup.egressProxy.serviceName,
    egressProxySecretName: parsed.cleanup.egressProxy.secretName,
  };
  for (const [key, value] of Object.entries(resourceNames)) {
    validateKubernetesResourceName(value, `defaults.cleanup.${key}`);
  }
  return parsed;
}

function parseDependencyImages(root: Record<string, unknown>): Sub2ApiConfig["dependencyImages"] {
  const value = root.dependencyImages;
  if (value === undefined) throw new Error(`${configPath}.dependencyImages must be an object`);
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${configPath}.dependencyImages must be an object`);
  const record = value as Record<string, unknown>;
  const postgres = stringField(record, "postgres", "dependencyImages");
  const redis = stringField(record, "redis", "dependencyImages");
  if (!isImageReference(postgres)) throw new Error(`${configPath}.dependencyImages.postgres has an unsupported format`);
  if (!isImageReference(redis)) throw new Error(`${configPath}.dependencyImages.redis has an unsupported format`);
  return { postgres, redis };
}

function parseTargets(root: Record<string, unknown>, defaultTargetId: string): Sub2ApiTargetConfig[] {
  const value = root.targets;
  if (value === undefined) throw new Error(`${configPath}.targets must be an array`);
  if (!Array.isArray(value)) throw new Error(`${configPath}.targets must be an array`);
  const targets = value.map((item, index) => {
    if (typeof item !== "object" || item === null || Array.isArray(item)) throw new Error(`${configPath}.targets[${index}] must be an object`);
    const record = item as Record<string, unknown>;
    const path = `targets[${index}]`;
    const id = stringField(record, "id", path);
    const route = stringField(record, "route", path);
    const targetNamespace = stringField(record, "namespace", path);
    const role = stringField(record, "role", path);
    const enabled = booleanField(record, "enabled", path);
    const databaseMode = enumField(record, "databaseMode", path, ["bundled", "external-pending", "external-active"] as const);
    const redisMode = enumField(record, "redisMode", path, ["bundled-persistent", "local-ephemeral"] as const);
    const appReplicas = integerField(record, "appReplicas", path);
    const redisReplicas = integerField(record, "redisReplicas", path);
    const image = targetImageOverride(record, path);
    const dependencyImages = targetDependencyImageOverride(record, path);
    const publicExposure = parsePublicExposureConfig(record.publicExposure, path);
    const egressProxy = parseEgressProxyConfig(record.egressProxy, path);
    if (!/^[A-Za-z0-9._-]+$/u.test(id)) throw new Error(`${configPath}.${path}.id must be a simple target id`);
    if (!/^[A-Za-z0-9:_./-]+$/u.test(route)) throw new Error(`${configPath}.${path}.route has an unsupported format`);
    if (!isKubernetesName(targetNamespace)) throw new Error(`${configPath}.${path}.namespace must be a Kubernetes namespace name`);
    if (appReplicas < 0) throw new Error(`${configPath}.${path}.appReplicas must be >= 0`);
    if (redisReplicas < 0) throw new Error(`${configPath}.${path}.redisReplicas must be >= 0`);
    return { id, route, namespace: targetNamespace, role, enabled, databaseMode, redisMode, appReplicas, redisReplicas, image, dependencyImages, publicExposure, egressProxy };
  });
  const ids = new Set<string>();
  for (const target of targets) {
    if (ids.has(target.id)) throw new Error(`${configPath}.targets contains duplicate id ${target.id}`);
    ids.add(target.id);
  }
  if (!ids.has(defaultTargetId)) throw new Error(`${configPath}.targets must include defaults.targetId ${defaultTargetId}`);
  return targets;
}

function targetImageOverride(record: Record<string, unknown>, path: string): Partial<Sub2ApiConfig["image"]> {
  if (record.image === undefined) return {};
  const image = objectField(record, "image", path);
  const override: Partial<Sub2ApiConfig["image"]> = {};
  if (image.repository !== undefined) {
    const repository = stringField(image, "repository", `${path}.image`);
    if (!isImageRepository(repository)) throw new Error(`${configPath}.${path}.image.repository has an unsupported format`);
    override.repository = repository;
  }
  if (image.tag !== undefined) {
    const tag = stringField(image, "tag", `${path}.image`);
    if (!/^[A-Za-z0-9._-]+$/u.test(tag)) throw new Error(`${configPath}.${path}.image.tag has an unsupported format`);
    override.tag = tag;
  }
  if (image.pullPolicy !== undefined) {
    override.pullPolicy = enumField(image, "pullPolicy", `${path}.image`, ["Always", "IfNotPresent", "Never"] as const);
  }
  return override;
}

function targetDependencyImageOverride(record: Record<string, unknown>, path: string): Partial<Sub2ApiConfig["dependencyImages"]> {
  if (record.dependencyImages === undefined) return {};
  const dependencyImages = objectField(record, "dependencyImages", path);
  const override: Partial<Sub2ApiConfig["dependencyImages"]> = {};
  if (dependencyImages.postgres !== undefined) {
    const postgres = stringField(dependencyImages, "postgres", `${path}.dependencyImages`);
    if (!isImageReference(postgres)) throw new Error(`${configPath}.${path}.dependencyImages.postgres has an unsupported format`);
    override.postgres = postgres;
  }
  if (dependencyImages.redis !== undefined) {
    const redis = stringField(dependencyImages, "redis", `${path}.dependencyImages`);
    if (!isImageReference(redis)) throw new Error(`${configPath}.${path}.dependencyImages.redis has an unsupported format`);
    override.redis = redis;
  }
  return override;
}

function parsePublicExposureConfig(value: unknown, path: string): Sub2ApiPublicExposureConfig | null {
  if (value === undefined || value === null) return null;
  if (typeof value !== "object" || Array.isArray(value)) throw new Error(`${configPath}.${path}.publicExposure must be an object`);
  const record = value as Record<string, unknown>;
  const enabled = booleanField(record, "enabled", `${path}.publicExposure`);
  const publicBaseUrl = stringField(record, "publicBaseUrl", `${path}.publicExposure`);
  const dnsRaw = objectField(record, "dns", `${path}.publicExposure`);
  const frpcRaw = objectField(record, "frpc", `${path}.publicExposure`);
  const pk01Raw = objectField(record, "pk01", `${path}.publicExposure`);
  const hostname = stringField(dnsRaw, "hostname", `${path}.publicExposure.dns`);
  const expectedA = stringField(dnsRaw, "expectedA", `${path}.publicExposure.dns`);
  const resolvers = stringArrayField(dnsRaw, "resolvers", `${path}.publicExposure.dns`);
  const exposure: Sub2ApiPublicExposureConfig = {
    enabled,
    publicBaseUrl: normalizePublicBaseUrl(publicBaseUrl, `${path}.publicExposure.publicBaseUrl`),
    dns: {
      hostname,
      expectedA,
      resolvers,
    },
    frpc: {
      deploymentName: stringField(frpcRaw, "deploymentName", `${path}.publicExposure.frpc`),
      secretName: stringField(frpcRaw, "secretName", `${path}.publicExposure.frpc`),
      secretKey: stringField(frpcRaw, "secretKey", `${path}.publicExposure.frpc`),
      image: stringField(frpcRaw, "image", `${path}.publicExposure.frpc`),
      serverAddr: stringField(frpcRaw, "serverAddr", `${path}.publicExposure.frpc`),
      serverPort: integerField(frpcRaw, "serverPort", `${path}.publicExposure.frpc`),
      proxyName: stringField(frpcRaw, "proxyName", `${path}.publicExposure.frpc`),
      remotePort: integerField(frpcRaw, "remotePort", `${path}.publicExposure.frpc`),
      localIP: stringField(frpcRaw, "localIP", `${path}.publicExposure.frpc`),
      localPort: integerField(frpcRaw, "localPort", `${path}.publicExposure.frpc`),
      tokenSourceRef: stringField(frpcRaw, "tokenSourceRef", `${path}.publicExposure.frpc`),
      tokenSourceKey: stringField(frpcRaw, "tokenSourceKey", `${path}.publicExposure.frpc`),
    },
    pk01: {
      route: stringField(pk01Raw, "route", `${path}.publicExposure.pk01`),
      caddyBinaryPath: stringField(pk01Raw, "caddyBinaryPath", `${path}.publicExposure.pk01`),
      caddyDownloadUrl: stringField(pk01Raw, "caddyDownloadUrl", `${path}.publicExposure.pk01`),
      caddyDownloadProxyUrl: pk01Raw.caddyDownloadProxyUrl === undefined ? null : stringField(pk01Raw, "caddyDownloadProxyUrl", `${path}.publicExposure.pk01`),
      caddyConfigPath: stringField(pk01Raw, "caddyConfigPath", `${path}.publicExposure.pk01`),
      caddyServiceName: stringField(pk01Raw, "caddyServiceName", `${path}.publicExposure.pk01`),
      caddyStorageDir: stringField(pk01Raw, "caddyStorageDir", `${path}.publicExposure.pk01`),
      caddyEmail: stringField(pk01Raw, "caddyEmail", `${path}.publicExposure.pk01`),
      pikanodeRoot: stringField(pk01Raw, "pikanodeRoot", `${path}.publicExposure.pk01`),
      pikanodeContainerName: stringField(pk01Raw, "pikanodeContainerName", `${path}.publicExposure.pk01`),
      pikanodeImage: stringField(pk01Raw, "pikanodeImage", `${path}.publicExposure.pk01`),
      pikanodeHttpHostPort: integerField(pk01Raw, "pikanodeHttpHostPort", `${path}.publicExposure.pk01`),
      responseHeaderTimeoutSeconds: integerField(pk01Raw, "responseHeaderTimeoutSeconds", `${path}.publicExposure.pk01`),
    },
  };
  validatePublicExposureConfig(exposure, path);
  return exposure;
}

function parseEgressProxyConfig(value: unknown, path: string): Sub2ApiEgressProxyConfig | null {
  if (value === undefined || value === null) return null;
  if (typeof value !== "object" || Array.isArray(value)) throw new Error(`${configPath}.${path}.egressProxy must be an object`);
  const record = value as Record<string, unknown>;
  const sourceType = enumField(record, "sourceType", `${path}.egressProxy`, ["subscription-url"] as const);
  const preferredOutbound = enumField(record, "preferredOutbound", `${path}.egressProxy`, ["vless-reality", "hysteria2"] as const);
  const imagePullPolicy = enumField(record, "imagePullPolicy", `${path}.egressProxy`, ["Always", "IfNotPresent", "Never"] as const);
  const noProxy = stringArrayField(record, "noProxy", `${path}.egressProxy`);
  const proxy: Sub2ApiEgressProxyConfig = {
    enabled: booleanField(record, "enabled", `${path}.egressProxy`),
    deploymentName: stringField(record, "deploymentName", `${path}.egressProxy`),
    serviceName: stringField(record, "serviceName", `${path}.egressProxy`),
    secretName: stringField(record, "secretName", `${path}.egressProxy`),
    secretKey: stringField(record, "secretKey", `${path}.egressProxy`),
    image: stringField(record, "image", `${path}.egressProxy`),
    imagePullPolicy,
    listenPort: integerField(record, "listenPort", `${path}.egressProxy`),
    sourceRef: stringField(record, "sourceRef", `${path}.egressProxy`),
    sourceKey: stringField(record, "sourceKey", `${path}.egressProxy`),
    sourceType,
    preferredOutbound,
    noProxy,
    applyToSub2Api: booleanField(record, "applyToSub2Api", `${path}.egressProxy`),
    applyToSentinel: booleanField(record, "applyToSentinel", `${path}.egressProxy`),
    healthProbeUrl: stringField(record, "healthProbeUrl", `${path}.egressProxy`),
  };
  validateEgressProxyConfig(proxy, path);
  return proxy;
}

function parseRuntime(root: Record<string, unknown>): Sub2ApiConfig["runtime"] {
  const value = root.runtime;
  if (value === undefined) throw new Error(`${configPath}.runtime must be an object`);
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${configPath}.runtime must be an object`);
  const runtime = value as Record<string, unknown>;
  const database = objectField(runtime, "database", "runtime");
  const databaseMode = enumField(database, "mode", "runtime.database", ["external"] as const);
  const sourceRef = stringField(database, "sourceRef", "runtime.database");
  const sourceKeysRaw = objectField(database, "sourceKeys", "runtime.database");
  const sourceKeys = {
    user: stringField(sourceKeysRaw, "user", "runtime.database.sourceKeys"),
    password: stringField(sourceKeysRaw, "password", "runtime.database.sourceKeys"),
    dbName: stringField(sourceKeysRaw, "dbName", "runtime.database.sourceKeys"),
  };
  const secret = stringField(database, "secretName", "runtime.database");
  const passwordKey = stringField(database, "passwordKey", "runtime.database");
  const host = stringField(database, "host", "runtime.database");
  const port = integerField(database, "port", "runtime.database");
  const user = stringField(database, "user", "runtime.database");
  const dbName = stringField(database, "dbName", "runtime.database");
  const sslMode = stringField(database, "sslMode", "runtime.database");
  const pendingAllowed = booleanField(database, "pendingAllowed", "runtime.database");
  if (!isKubernetesName(secret)) throw new Error(`${configPath}.runtime.database.secretName must be a Kubernetes Secret name`);
  if (!/^[A-Za-z0-9_./-]+$/u.test(sourceRef)) throw new Error(`${configPath}.runtime.database.sourceRef has an unsupported format`);
  for (const [key, value] of Object.entries(sourceKeys)) {
    if (!/^[A-Z0-9_]+$/u.test(value)) throw new Error(`${configPath}.runtime.database.sourceKeys.${key} must be an env key`);
  }
  if (!/^[A-Z0-9_]+$/u.test(passwordKey)) throw new Error(`${configPath}.runtime.database.passwordKey must be an env key`);
  if (!/^[A-Za-z0-9._-]+$/u.test(host)) throw new Error(`${configPath}.runtime.database.host has an unsupported format`);
  if (!/^[A-Za-z0-9_][-A-Za-z0-9_]*$/u.test(user)) throw new Error(`${configPath}.runtime.database.user has an unsupported format`);
  if (!/^[A-Za-z0-9_][-A-Za-z0-9_]*$/u.test(dbName)) throw new Error(`${configPath}.runtime.database.dbName has an unsupported format`);
  if (!/^[A-Za-z0-9_-]+$/u.test(sslMode)) throw new Error(`${configPath}.runtime.database.sslMode has an unsupported format`);
  if (port < 1 || port > 65535) throw new Error(`${configPath}.runtime.database.port must be a TCP port`);
  if (databaseMode !== "external") throw new Error(`${configPath}.runtime.database.mode must be external`);
  const redis = objectField(runtime, "redis", "runtime");
  const redisServiceName = stringField(redis, "serviceName", "runtime.redis");
  const redisPersistence = booleanField(redis, "persistence", "runtime.redis");
  if (!isKubernetesName(redisServiceName)) throw new Error(`${configPath}.runtime.redis.serviceName must be a Kubernetes Service name`);
  const secretsRaw = objectField(runtime, "secrets", "runtime");
  const secretRoot = stringField(secretsRaw, "root", "runtime.secrets");
  const appSourceRef = stringField(secretsRaw, "appSourceRef", "runtime.secrets");
  if (!/^[A-Za-z0-9_./-]+$/u.test(secretRoot)) throw new Error(`${configPath}.runtime.secrets.root has an unsupported format`);
  if (!/^[A-Za-z0-9_./-]+$/u.test(appSourceRef)) throw new Error(`${configPath}.runtime.secrets.appSourceRef has an unsupported format`);
  const appData = objectField(runtime, "appData", "runtime");
  const appDataMode = enumField(appData, "mode", "runtime.appData", ["persistent-pvc", "empty-dir"] as const);
  const sentinel = objectField(runtime, "sentinel", "runtime");
  const sentinelMode = enumField(sentinel, "mode", "runtime.sentinel", ["singleton"] as const);
  const enabledOnTargets = stringArrayField(sentinel, "enabledOnTargets", "runtime.sentinel");
  if (sentinelMode !== "singleton") throw new Error(`${configPath}.runtime.sentinel.mode must be singleton`);
  return {
    database: { mode: "external", sourceRef, sourceKeys, secretName: secret, passwordKey, host, port, user, dbName, sslMode, pendingAllowed },
    secrets: { root: secretRoot, appSourceRef },
    redis: { serviceName: redisServiceName, persistence: redisPersistence },
    appData: { mode: appDataMode },
    sentinel: { mode: "singleton", enabledOnTargets },
  };
}

function stringField(obj: Record<string, unknown>, key: string, path: string): string {
  const value = obj[key];
  if (typeof value !== "string" || value.length === 0) throw new Error(`${fieldLabel(path, key)} must be a non-empty string`);
  return value;
}

function objectField(obj: Record<string, unknown>, key: string, path: string): Record<string, unknown> {
  const value = obj[key];
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${fieldLabel(path, key)} must be an object`);
  return value as Record<string, unknown>;
}

function booleanField(obj: Record<string, unknown>, key: string, path: string): boolean {
  return yamlBooleanField(obj, key, configPath, path);
}

function stringArrayField(obj: Record<string, unknown>, key: string, path: string): string[] {
  const value = obj[key];
  if (!Array.isArray(value) || !value.every((item) => typeof item === "string" && item.trim().length > 0)) {
    throw new Error(`${fieldLabel(path, key)} must be an array of non-empty strings`);
  }
  return value.map((item) => item.trim());
}

function enumField<const T extends readonly string[]>(obj: Record<string, unknown>, key: string, path: string, values: T): T[number] {
  const value = stringField(obj, key, path);
  if (!(values as readonly string[]).includes(value)) throw new Error(`${fieldLabel(path, key)} must be one of ${values.join(", ")}`);
  return value as T[number];
}

function integerField(obj: Record<string, unknown>, key: string, path: string): number {
  return yamlIntegerField(obj, key, configPath, path);
}

function integerArrayField(obj: Record<string, unknown>, key: string, path: string): number[] {
  const value = obj[key];
  if (!Array.isArray(value) || !value.every((item) => typeof item === "number" && Number.isInteger(item))) {
    throw new Error(`${fieldLabel(path, key)} must be an array of integers`);
  }
  return value;
}

function fieldLabel(path: string, key: string): string {
  return yamlFieldLabel(configPath, path, key);
}

function isKubernetesName(value: string): boolean {
  return /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/u.test(value);
}

function isImageRepository(value: string): boolean {
  return /^[A-Za-z0-9._:/-]+$/u.test(value) && !value.includes("..") && !value.includes("@") && !value.endsWith(":");
}

function isImageReference(value: string): boolean {
  return /^[A-Za-z0-9._:/-]+$/u.test(value) && value.includes(":") && !value.includes("..");
}

function validatePublicExposureConfig(config: Sub2ApiPublicExposureConfig, path: string): void {
  const url = new URL(config.publicBaseUrl);
  if (url.protocol !== "https:") throw new Error(`${configPath}.${path}.publicExposure.publicBaseUrl must use https://`);
  if (url.hostname !== config.dns.hostname) throw new Error(`${configPath}.${path}.publicExposure.publicBaseUrl hostname must match publicExposure.dns.hostname`);
  validateHostname(config.dns.hostname, `${path}.publicExposure.dns.hostname`);
  if (!/^[0-9.]+$/u.test(config.dns.expectedA)) throw new Error(`${configPath}.${path}.publicExposure.dns.expectedA must be an IPv4 address`);
  for (const resolver of config.dns.resolvers) {
    if (!/^[0-9.]+$/u.test(resolver)) throw new Error(`${configPath}.${path}.publicExposure.dns.resolvers entries must be IPv4 resolvers`);
  }
  validateKubernetesResourceName(config.frpc.deploymentName, `${path}.publicExposure.frpc.deploymentName`);
  validateKubernetesResourceName(config.frpc.secretName, `${path}.publicExposure.frpc.secretName`);
  if (config.frpc.secretKey !== "frpc.toml") throw new Error(`${configPath}.${path}.publicExposure.frpc.secretKey must be frpc.toml`);
  if (!isImageReference(config.frpc.image)) throw new Error(`${configPath}.${path}.publicExposure.frpc.image has an unsupported format`);
  validateHostOrIp(config.frpc.serverAddr, `${path}.publicExposure.frpc.serverAddr`);
  validatePort(config.frpc.serverPort, `${path}.publicExposure.frpc.serverPort`);
  validateProxyName(config.frpc.proxyName, `${path}.publicExposure.frpc.proxyName`);
  validatePort(config.frpc.remotePort, `${path}.publicExposure.frpc.remotePort`);
  validateHostOrIp(config.frpc.localIP, `${path}.publicExposure.frpc.localIP`);
  validatePort(config.frpc.localPort, `${path}.publicExposure.frpc.localPort`);
  if (!/^[A-Za-z0-9_./-]+$/u.test(config.frpc.tokenSourceRef)) throw new Error(`${configPath}.${path}.publicExposure.frpc.tokenSourceRef has an unsupported format`);
  if (!/^[A-Z0-9_]+$/u.test(config.frpc.tokenSourceKey)) throw new Error(`${configPath}.${path}.publicExposure.frpc.tokenSourceKey must be an env key`);
  if (!/^[A-Za-z0-9:_./-]+$/u.test(config.pk01.route)) throw new Error(`${configPath}.${path}.publicExposure.pk01.route has an unsupported format`);
  if (!config.pk01.caddyBinaryPath.startsWith("/")) throw new Error(`${configPath}.${path}.publicExposure.pk01.caddyBinaryPath must be absolute`);
  if (!/^https:\/\//u.test(config.pk01.caddyDownloadUrl)) throw new Error(`${configPath}.${path}.publicExposure.pk01.caddyDownloadUrl must use https://`);
  if (config.pk01.caddyDownloadProxyUrl !== null) validateProxyUrl(config.pk01.caddyDownloadProxyUrl, `${path}.publicExposure.pk01.caddyDownloadProxyUrl`);
  if (!config.pk01.caddyConfigPath.startsWith("/")) throw new Error(`${configPath}.${path}.publicExposure.pk01.caddyConfigPath must be absolute`);
  validateProxyName(config.pk01.caddyServiceName, `${path}.publicExposure.pk01.caddyServiceName`);
  if (!config.pk01.caddyStorageDir.startsWith("/")) throw new Error(`${configPath}.${path}.publicExposure.pk01.caddyStorageDir must be absolute`);
  if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/u.test(config.pk01.caddyEmail)) throw new Error(`${configPath}.${path}.publicExposure.pk01.caddyEmail must be an email address`);
  if (!config.pk01.pikanodeRoot.startsWith("/")) throw new Error(`${configPath}.${path}.publicExposure.pk01.pikanodeRoot must be absolute`);
  validateProxyName(config.pk01.pikanodeContainerName, `${path}.publicExposure.pk01.pikanodeContainerName`);
  if (!isImageRepository(config.pk01.pikanodeImage) && !isImageReference(config.pk01.pikanodeImage)) throw new Error(`${configPath}.${path}.publicExposure.pk01.pikanodeImage has an unsupported format`);
  validatePort(config.pk01.pikanodeHttpHostPort, `${path}.publicExposure.pk01.pikanodeHttpHostPort`);
  if (config.pk01.responseHeaderTimeoutSeconds < 1) throw new Error(`${configPath}.${path}.publicExposure.pk01.responseHeaderTimeoutSeconds must be >= 1`);
}

function validateEgressProxyConfig(config: Sub2ApiEgressProxyConfig, path: string): void {
  validateKubernetesResourceName(config.deploymentName, `${path}.egressProxy.deploymentName`);
  validateKubernetesResourceName(config.serviceName, `${path}.egressProxy.serviceName`);
  validateKubernetesResourceName(config.secretName, `${path}.egressProxy.secretName`);
  if (config.secretKey !== "config.json") throw new Error(`${configPath}.${path}.egressProxy.secretKey must be config.json`);
  if (!isImageReference(config.image)) throw new Error(`${configPath}.${path}.egressProxy.image has an unsupported format`);
  validatePort(config.listenPort, `${path}.egressProxy.listenPort`);
  if (!/^[A-Za-z0-9_./-]+$/u.test(config.sourceRef)) throw new Error(`${configPath}.${path}.egressProxy.sourceRef has an unsupported format`);
  if (!/^[A-Z0-9_]+$/u.test(config.sourceKey)) throw new Error(`${configPath}.${path}.egressProxy.sourceKey must be an env key`);
  for (const entry of config.noProxy) {
    if (!/^[A-Za-z0-9.:_/*-]+$/u.test(entry)) throw new Error(`${configPath}.${path}.egressProxy.noProxy contains an unsupported entry`);
  }
  const url = new URL(config.healthProbeUrl);
  if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error(`${configPath}.${path}.egressProxy.healthProbeUrl must use http:// or https://`);
}

function normalizePublicBaseUrl(value: string, path: string): string {
  let parsed: URL;
  try {
    parsed = new URL(value);
  } catch {
    throw new Error(`${configPath}.${path} must be a valid URL`);
  }
  parsed.pathname = parsed.pathname.replace(/\/+$/u, "");
  if (parsed.search || parsed.hash) throw new Error(`${configPath}.${path} must not include query or hash`);
  return parsed.toString().replace(/\/+$/u, "");
}

function validateHostname(value: string, path: string): void {
  if (!/^[A-Za-z0-9.-]+$/u.test(value) || !value.includes(".")) throw new Error(`${configPath}.${path} must be a hostname`);
}

function validateKubernetesResourceName(value: string, path: string): void {
  if (!isKubernetesName(value)) throw new Error(`${configPath}.${path} must be a Kubernetes resource name`);
}

function validateHostOrIp(value: string, path: string): void {
  if (!/^[A-Za-z0-9._:-]+$/u.test(value)) throw new Error(`${configPath}.${path} has an unsupported format`);
}

function validatePort(value: number, path: string): void {
  if (value < 1 || value > 65535) throw new Error(`${configPath}.${path} must be a TCP port`);
}

function validateProxyName(value: string, path: string): void {
  if (!/^[A-Za-z0-9._-]+$/u.test(value)) throw new Error(`${configPath}.${path} has an unsupported format`);
}

function validateProxyUrl(value: string, path: string): void {
  let url: URL;
  try {
    url = new URL(value);
  } catch {
    throw new Error(`${configPath}.${path} must be a valid proxy URL`);
  }
  if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error(`${configPath}.${path} must use http:// or https://`);
  if (url.username || url.password || url.search || url.hash) throw new Error(`${configPath}.${path} must not include credentials, query, or hash`);
}

function resolveTarget(sub2api: Sub2ApiConfig, targetId: string): Sub2ApiTargetConfig {
  const target = sub2api.targets.find((item) => item.id.toLowerCase() === targetId.toLowerCase());
  if (target === undefined) {
    const known = sub2api.targets.map((item) => item.id).join(", ");
    throw new Error(`unknown Sub2API target ${targetId}; known targets: ${known}`);
  }
  if (!target.enabled) throw new Error(`Sub2API target ${target.id} is disabled in ${configPath}`);
  return target;
}

function targetImage(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): Sub2ApiConfig["image"] {
  return {
    repository: target.image.repository ?? sub2api.image.repository,
    tag: target.image.tag ?? sub2api.image.tag,
    pullPolicy: target.image.pullPolicy ?? sub2api.image.pullPolicy,
  };
}

function targetDependencyImages(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): Sub2ApiConfig["dependencyImages"] {
  return {
    postgres: target.dependencyImages.postgres ?? sub2api.dependencyImages.postgres,
    redis: target.dependencyImages.redis ?? sub2api.dependencyImages.redis,
  };
}

function imageRef(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): string {
  const image = targetImage(sub2api, target);
  return `${image.repository}:${image.tag}`;
}

function isExternalTarget(target: Sub2ApiTargetConfig): boolean {
  return target.databaseMode === "external-pending" || target.databaseMode === "external-active";
}

function manifest(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): string {
  if (isExternalTarget(target)) return externalPendingManifest(sub2api, target);
  const template = readFileSync(manifestPath, "utf8");
  const urlAllowlist = sub2api.security.urlAllowlist;
  const configHash = configHashFor(sub2api, target);
  const image = targetImage(sub2api, target);
  const dependencyImages = targetDependencyImages(sub2api, target);
  return template
    .replaceAll("__SUB2API_IMAGE__", imageRef(sub2api, target))
    .replaceAll("__SUB2API_IMAGE_PULL_POLICY__", image.pullPolicy)
    .replaceAll("postgres:18-alpine", dependencyImages.postgres)
    .replaceAll("redis:8-alpine", dependencyImages.redis)
    .replaceAll("__SUB2API_CONFIG_HASH__", configHash)
    .replaceAll("__SUB2API_SECURITY_URL_ALLOWLIST_ENABLED__", String(urlAllowlist.enabled))
    .replaceAll("__SUB2API_SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP__", String(urlAllowlist.allowInsecureHttp))
    .replaceAll("__SUB2API_SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS__", String(urlAllowlist.allowPrivateHosts))
    .replaceAll("__SUB2API_SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS__", urlAllowlist.upstreamHosts.join(","));
}

function configHashFor(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): string {
  return createHash("sha256")
    .update(JSON.stringify({
      image: targetImage(sub2api, target),
      dependencyImages: targetDependencyImages(sub2api, target),
      security: sub2api.security,
      target,
      runtime: sub2api.runtime,
    }))
    .digest("hex")
    .slice(0, 16);
}

function targetHasSentinel(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): boolean {
  return sub2api.runtime.sentinel.enabledOnTargets.some((id) => id.toLowerCase() === target.id.toLowerCase());
}

function managedResourceCleanupPlan(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): ManagedResourceCleanupPlan {
  const sentinel = codexPoolSentinelResourceNames();
  return {
    externalDbState: {
      enabled: isExternalTarget(target),
      ...sub2api.defaults.cleanup.externalDbState,
    },
    redisPersistentState: {
      enabled: target.redisMode === "local-ephemeral",
      ...sub2api.defaults.cleanup.redisPersistentState,
    },
    publicExposure: {
      enabled: target.publicExposure?.enabled === true,
      deploymentName: target.publicExposure?.frpc.deploymentName ?? sub2api.defaults.cleanup.publicExposure.deploymentName,
      configMapName: sub2api.defaults.cleanup.publicExposure.configMapName,
      secretName: target.publicExposure?.frpc.secretName ?? sub2api.defaults.cleanup.publicExposure.secretName,
    },
    egressProxy: {
      enabled: target.egressProxy?.enabled === true,
      deploymentName: target.egressProxy?.deploymentName ?? sub2api.defaults.cleanup.egressProxy.deploymentName,
      serviceName: target.egressProxy?.serviceName ?? sub2api.defaults.cleanup.egressProxy.serviceName,
      secretName: target.egressProxy?.secretName ?? sub2api.defaults.cleanup.egressProxy.secretName,
    },
    sentinel: {
      ...sentinel,
      enabled: targetHasSentinel(sub2api, target),
    },
  };
}

function codexPoolSentinelResourceNames(): ManagedResourceCleanupPlan["sentinel"] {
  if (!existsSync(codexPoolConfigPath)) throw new Error(`${codexPoolConfigPath} is required for Sub2API codex-pool sentinel cleanup resource names`);
  const parsed = Bun.YAML.parse(readFileSync(codexPoolConfigPath, "utf8")) as unknown;
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error(`${codexPoolConfigPath} must be an object`);
  const sentinel = (parsed as Record<string, unknown>).sentinel;
  if (typeof sentinel !== "object" || sentinel === null || Array.isArray(sentinel)) throw new Error(`${codexPoolConfigPath}.sentinel must be an object`);
  const record = sentinel as Record<string, unknown>;
  const resourceName = (key: string): string => {
    const value = stringField(record, key, "sentinel");
    validateKubernetesResourceName(value, `sentinel.${key}`);
    return value;
  };
  return {
    enabled: false,
    cronJobName: resourceName("cronJobName"),
    configMapName: resourceName("configMapName"),
    credentialsSecretName: resourceName("credentialsSecretName"),
    stateConfigMapName: resourceName("stateConfigMapName"),
    serviceAccountName: resourceName("serviceAccountName"),
    roleName: resourceName("roleName"),
    roleBindingName: resourceName("roleBindingName"),
  };
}

function externalPendingManifest(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): string {
  const urlAllowlist = sub2api.security.urlAllowlist;
  const database = sub2api.runtime.database;
  const databaseStatus = target.databaseMode === "external-active" ? "external-db-active" : "pending-external-db";
  const redisService = sub2api.runtime.redis.serviceName;
  const appReplicas = target.appReplicas;
  const redisReplicas = target.redisReplicas;
  const image = targetImage(sub2api, target);
  const dependencyImages = targetDependencyImages(sub2api, target);
  const publicExposure = renderPublicExposureManifest(target);
  const egressProxy = renderEgressProxyManifest(target);
  const proxyEnv = sub2ApiProxyEnv(target);
  return `apiVersion: v1
kind: Namespace
metadata:
  name: ${target.namespace}
  labels:
    app.kubernetes.io/name: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: ${target.id}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: platform-infra
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - {}
  egress:
    - {}
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: sub2api-config
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: sub2api
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: ${target.id}
data:
  AUTO_SETUP: "true"
  SERVER_HOST: "0.0.0.0"
  SERVER_PORT: "8080"
  SERVER_MODE: "release"
  RUN_MODE: "standard"
  DATABASE_HOST: "${database.host}"
  DATABASE_PORT: "${database.port}"
  DATABASE_USER: "${database.user}"
  DATABASE_DBNAME: "${database.dbName}"
  DATABASE_SSLMODE: "${database.sslMode}"
  DATABASE_MAX_OPEN_CONNS: "10"
  DATABASE_MAX_IDLE_CONNS: "2"
  DATABASE_CONN_MAX_LIFETIME_MINUTES: "30"
  DATABASE_CONN_MAX_IDLE_TIME_MINUTES: "5"
  REDIS_HOST: "${redisService}"
  REDIS_PORT: "6379"
  REDIS_PASSWORD: ""
  REDIS_DB: "0"
  REDIS_POOL_SIZE: "32"
  REDIS_MIN_IDLE_CONNS: "2"
  REDIS_ENABLE_TLS: "false"
  ADMIN_EMAIL: "admin@sub2api.platform-infra.local"
  JWT_EXPIRE_HOUR: "24"
  TZ: "Asia/Shanghai"
  SECURITY_URL_ALLOWLIST_ENABLED: "${urlAllowlist.enabled}"
  SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP: "${urlAllowlist.allowInsecureHttp}"
  SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS: "${urlAllowlist.allowPrivateHosts}"
  SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS: "${urlAllowlist.upstreamHosts.join(",")}"
  UPDATE_PROXY_URL: "${proxyEnv.httpProxy}"
  HTTP_PROXY: "${proxyEnv.httpProxy}"
  HTTPS_PROXY: "${proxyEnv.httpProxy}"
  ALL_PROXY: "${proxyEnv.httpProxy}"
  http_proxy: "${proxyEnv.httpProxy}"
  https_proxy: "${proxyEnv.httpProxy}"
  all_proxy: "${proxyEnv.httpProxy}"
  NO_PROXY: "${proxyEnv.noProxy}"
  no_proxy: "${proxyEnv.noProxy}"
  GATEWAY_OPENAI_RESPONSE_HEADER_TIMEOUT: "0"
  GATEWAY_OPENAI_HTTP2_ENABLED: "true"
  GATEWAY_OPENAI_HTTP2_ALLOW_PROXY_FALLBACK_TO_HTTP1: "true"
  GATEWAY_OPENAI_HTTP2_FALLBACK_ERROR_THRESHOLD: "2"
  GATEWAY_OPENAI_HTTP2_FALLBACK_WINDOW_SECONDS: "60"
  GATEWAY_OPENAI_HTTP2_FALLBACK_TTL_SECONDS: "600"
  GATEWAY_IMAGE_STREAM_DATA_INTERVAL_TIMEOUT: "900"
  GATEWAY_IMAGE_STREAM_KEEPALIVE_INTERVAL: "10"
  GATEWAY_IMAGE_CONCURRENCY_ENABLED: "false"
  GATEWAY_IMAGE_CONCURRENCY_MAX_CONCURRENT_REQUESTS: "0"
  GATEWAY_IMAGE_CONCURRENCY_OVERFLOW_MODE: "reject"
  GATEWAY_IMAGE_CONCURRENCY_WAIT_TIMEOUT_SECONDS: "30"
  GATEWAY_IMAGE_CONCURRENCY_MAX_WAITING_REQUESTS: "100"
---
apiVersion: v1
kind: Service
metadata:
  name: ${redisService}
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: sub2api-redis
    app.kubernetes.io/component: redis
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: ${target.id}
    unidesk.ai/state-mode: ephemeral-cache
spec:
  selector:
    app.kubernetes.io/name: sub2api-redis
    app.kubernetes.io/component: redis
  ports:
    - name: redis
      port: 6379
      targetPort: redis
---
apiVersion: v1
kind: Service
metadata:
  name: sub2api
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: sub2api
    app.kubernetes.io/component: app
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: ${target.id}
spec:
  selector:
    app.kubernetes.io/name: sub2api
    app.kubernetes.io/component: app
  ports:
    - name: http
      port: 8080
      targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sub2api-redis
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: sub2api-redis
    app.kubernetes.io/component: redis
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: ${target.id}
    unidesk.ai/state-mode: ephemeral-cache
spec:
  replicas: ${redisReplicas}
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app.kubernetes.io/name: sub2api-redis
      app.kubernetes.io/component: redis
  template:
    metadata:
      labels:
        app.kubernetes.io/name: sub2api-redis
        app.kubernetes.io/component: redis
        app.kubernetes.io/part-of: platform-infra
    spec:
      securityContext:
        fsGroup: 999
      containers:
        - name: redis
          image: ${dependencyImages.redis}
          imagePullPolicy: IfNotPresent
          command:
            - sh
            - -c
          args:
            - redis-server --save "" --appendonly no
          ports:
            - name: redis
              containerPort: 6379
          env:
            - name: TZ
              value: Asia/Shanghai
          readinessProbe:
            exec:
              command:
                - redis-cli
                - ping
            initialDelaySeconds: 5
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 6
          livenessProbe:
            exec:
              command:
                - redis-cli
                - ping
            initialDelaySeconds: 30
            periodSeconds: 20
            timeoutSeconds: 5
            failureThreshold: 6
          volumeMounts:
            - name: redis-data
              mountPath: /data
      volumes:
        - name: redis-data
          emptyDir: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sub2api
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: sub2api
    app.kubernetes.io/component: app
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: ${target.id}
    unidesk.ai/database-status: ${databaseStatus}
spec:
  replicas: ${appReplicas}
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app.kubernetes.io/name: sub2api
      app.kubernetes.io/component: app
  template:
    metadata:
      annotations:
        unidesk.ai/sub2api-config-hash: "${configHashFor(sub2api, target)}"
        unidesk.ai/database-source-ref: "${database.sourceRef}"
        unidesk.ai/database-status: "${databaseStatus}"
      labels:
        app.kubernetes.io/name: sub2api
        app.kubernetes.io/component: app
        app.kubernetes.io/part-of: platform-infra
    spec:
      securityContext:
        fsGroup: 1000
      initContainers:
        - name: wait-postgres
          image: ${dependencyImages.postgres}
          imagePullPolicy: IfNotPresent
          command:
            - sh
            - -c
            - until pg_isready -h ${database.host} -p ${database.port} -U ${database.user} -d ${database.dbName}; do sleep 2; done
        - name: wait-redis
          image: ${dependencyImages.redis}
          imagePullPolicy: IfNotPresent
          command:
            - sh
            - -c
            - until redis-cli -h ${redisService} ping | grep -q PONG; do sleep 2; done
      containers:
        - name: sub2api
          image: ${imageRef(sub2api, target)}
          imagePullPolicy: ${image.pullPolicy}
          ports:
            - name: http
              containerPort: 8080
          envFrom:
            - configMapRef:
                name: sub2api-config
          env:
            - name: DATABASE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: ${database.secretName}
                  key: ${database.passwordKey}
            - name: ADMIN_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: ${database.secretName}
                  key: ADMIN_PASSWORD
            - name: JWT_SECRET
              valueFrom:
                secretKeyRef:
                  name: ${database.secretName}
                  key: JWT_SECRET
            - name: TOTP_ENCRYPTION_KEY
              valueFrom:
                secretKeyRef:
                  name: ${database.secretName}
                  key: TOTP_ENCRYPTION_KEY
          readinessProbe:
            httpGet:
              path: /health
              port: http
            initialDelaySeconds: 10
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 6
          livenessProbe:
            httpGet:
              path: /health
              port: http
            initialDelaySeconds: 30
            periodSeconds: 20
            timeoutSeconds: 5
            failureThreshold: 6
          startupProbe:
            httpGet:
              path: /health
              port: http
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 30
          volumeMounts:
            - name: sub2api-data
              mountPath: /app/data
      volumes:
        - name: sub2api-data
          emptyDir: {}
${publicExposure}
${egressProxy}
`;
}

function sub2ApiProxyEnv(target: Sub2ApiTargetConfig): { httpProxy: string; noProxy: string } {
  const proxy = target.egressProxy;
  if (proxy === null || !proxy.enabled || !proxy.applyToSub2Api) return { httpProxy: "", noProxy: "" };
  return {
    httpProxy: `http://${proxy.serviceName}.${target.namespace}.svc.cluster.local:${proxy.listenPort}`,
    noProxy: proxy.noProxy.join(","),
  };
}

function renderPublicExposureManifest(target: Sub2ApiTargetConfig): string {
  const exposure = target.publicExposure;
  if (exposure === null || !exposure.enabled) return "";
  return `---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ${exposure.frpc.deploymentName}
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: ${exposure.frpc.deploymentName}
    app.kubernetes.io/component: tunnel
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: ${target.id}
    unidesk.ai/public-hostname: ${exposure.dns.hostname}
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: ${exposure.frpc.deploymentName}
      app.kubernetes.io/component: tunnel
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ${exposure.frpc.deploymentName}
        app.kubernetes.io/component: tunnel
        app.kubernetes.io/part-of: platform-infra
      annotations:
        unidesk.ai/public-base-url: "${exposure.publicBaseUrl}"
        unidesk.ai/frp-server: "${exposure.frpc.serverAddr}:${exposure.frpc.serverPort}"
        unidesk.ai/frp-remote-port: "${exposure.frpc.remotePort}"
    spec:
      containers:
        - name: frpc
          image: ${exposure.frpc.image}
          imagePullPolicy: IfNotPresent
          args:
            - -c
            - /etc/frp/frpc.toml
          volumeMounts:
            - name: frpc-config
              mountPath: /etc/frp/frpc.toml
              subPath: ${exposure.frpc.secretKey}
              readOnly: true
      volumes:
        - name: frpc-config
          secret:
            secretName: ${exposure.frpc.secretName}
`;
}

function renderEgressProxyManifest(target: Sub2ApiTargetConfig): string {
  const proxy = target.egressProxy;
  if (proxy === null || !proxy.enabled) return "";
  return `---
apiVersion: v1
kind: Service
metadata:
  name: ${proxy.serviceName}
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: ${proxy.deploymentName}
    app.kubernetes.io/component: egress-proxy
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: ${target.id}
    unidesk.ai/proxy-source: master-vpn-subscription
spec:
  selector:
    app.kubernetes.io/name: ${proxy.deploymentName}
    app.kubernetes.io/component: egress-proxy
  ports:
    - name: http
      port: ${proxy.listenPort}
      targetPort: proxy
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ${proxy.deploymentName}
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: ${proxy.deploymentName}
    app.kubernetes.io/component: egress-proxy
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: ${target.id}
    unidesk.ai/proxy-source: master-vpn-subscription
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: ${proxy.deploymentName}
      app.kubernetes.io/component: egress-proxy
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ${proxy.deploymentName}
        app.kubernetes.io/component: egress-proxy
        app.kubernetes.io/part-of: platform-infra
      annotations:
        unidesk.ai/proxy-source-ref: "${proxy.sourceRef}"
        unidesk.ai/proxy-preferred-outbound: "${proxy.preferredOutbound}"
    spec:
      containers:
        - name: proxy
          image: ${proxy.image}
          imagePullPolicy: ${proxy.imagePullPolicy}
          args:
            - run
            - -c
            - /etc/sing-box/${proxy.secretKey}
          ports:
            - name: proxy
              containerPort: ${proxy.listenPort}
          readinessProbe:
            tcpSocket:
              port: proxy
            initialDelaySeconds: 5
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 6
          livenessProbe:
            tcpSocket:
              port: proxy
            initialDelaySeconds: 30
            periodSeconds: 20
            timeoutSeconds: 5
            failureThreshold: 6
          volumeMounts:
            - name: proxy-config
              mountPath: /etc/sing-box/${proxy.secretKey}
              subPath: ${proxy.secretKey}
              readOnly: true
      volumes:
        - name: proxy-config
          secret:
            secretName: ${proxy.secretName}
`;
}

function publicExposureSummary(exposure: Sub2ApiPublicExposureConfig): Record<string, unknown> {
  return {
    enabled: exposure.enabled,
    publicBaseUrl: exposure.publicBaseUrl,
    dns: exposure.dns,
    frpc: {
      deploymentName: exposure.frpc.deploymentName,
      secretName: exposure.frpc.secretName,
      image: exposure.frpc.image,
      serverAddr: exposure.frpc.serverAddr,
      serverPort: exposure.frpc.serverPort,
      proxyName: exposure.frpc.proxyName,
      remotePort: exposure.frpc.remotePort,
      localIP: exposure.frpc.localIP,
      localPort: exposure.frpc.localPort,
      tokenSourceRef: exposure.frpc.tokenSourceRef,
      valuesPrinted: false,
    },
    pk01: {
      route: exposure.pk01.route,
      mode: "caddy-edge",
      caddyBinaryPath: exposure.pk01.caddyBinaryPath,
      caddyDownloadProxyUrl: exposure.pk01.caddyDownloadProxyUrl,
      caddyConfigPath: exposure.pk01.caddyConfigPath,
      caddyServiceName: exposure.pk01.caddyServiceName,
      pikanodeHttpHostPort: exposure.pk01.pikanodeHttpHostPort,
    },
  };
}

function egressProxySummary(proxy: Sub2ApiEgressProxyConfig): Record<string, unknown> {
  return {
    enabled: proxy.enabled,
    mode: "master-vpn-subscription-http-proxy",
    deploymentName: proxy.deploymentName,
    serviceName: proxy.serviceName,
    secretName: proxy.secretName,
    image: proxy.image,
    imagePullPolicy: proxy.imagePullPolicy,
    listenPort: proxy.listenPort,
    sourceRef: proxy.sourceRef,
    sourceType: proxy.sourceType,
    preferredOutbound: proxy.preferredOutbound,
    applyToSub2Api: proxy.applyToSub2Api,
    applyToSentinel: proxy.applyToSentinel,
    healthProbeUrl: proxy.healthProbeUrl,
    noProxy: proxy.noProxy,
    valuesPrinted: false,
  };
}

function plan(options: TargetOptions): Record<string, unknown> {
  const sub2api = readSub2ApiConfig();
  const target = resolveTarget(sub2api, options.targetId);
  const yaml = manifest(sub2api, target);
  const policy = policyChecks(sub2api, yaml, target);
  return {
    ok: policy.every((check) => check.ok),
    action: "platform-infra-sub2api-plan",
    target: {
      id: target.id,
      route: target.route,
      namespace: target.namespace,
      role: target.role,
      manifestPath,
      configPath,
      fieldManager,
      serviceDns: `${serviceName}.${target.namespace}.svc.cluster.local:8080`,
    },
    config: {
      path: configPath,
      version: sub2api.version,
      kind: sub2api.kind,
      metadata: sub2api.metadata,
      image: imageRef(sub2api, target),
      pullPolicy: targetImage(sub2api, target).pullPolicy,
      dependencyImages: targetDependencyImages(sub2api, target),
      security: sub2api.security,
      target: {
        databaseMode: target.databaseMode,
        redisMode: target.redisMode,
        appReplicas: target.appReplicas,
        redisReplicas: target.redisReplicas,
        publicExposure: target.publicExposure === null ? null : publicExposureSummary(target.publicExposure),
        egressProxy: target.egressProxy === null ? null : egressProxySummary(target.egressProxy),
      },
      externalDatabase: isExternalTarget(target) ? {
        status: target.databaseMode === "external-active" ? "external-db-active" : "pending-external-db",
        sourceRef: sub2api.runtime.database.sourceRef,
        sourceKeys: sub2api.runtime.database.sourceKeys,
        secretName: sub2api.runtime.database.secretName,
        passwordKey: sub2api.runtime.database.passwordKey,
        host: sub2api.runtime.database.host,
        port: sub2api.runtime.database.port,
        user: sub2api.runtime.database.user,
        dbName: sub2api.runtime.database.dbName,
        sslMode: sub2api.runtime.database.sslMode,
        pendingAllowed: sub2api.runtime.database.pendingAllowed,
      } : null,
    },
    decision: {
      owner: "UniDesk",
      namespace: target.namespace,
      reason: target.databaseMode === "external-pending"
        ? `${target.id} is a standby Sub2API platform-infra target prepared through YAML; it stays scaled to zero until this target is promoted in YAML.`
        : target.databaseMode === "external-active"
          ? `${target.id} is activated as a platform-infra Sub2API target against the external PK01 PostgreSQL runtime while keeping app state outside the k3s node.`
          : `${target.id} is a bundled active Sub2API platform-infra target.`,
      exposure: target.publicExposure?.enabled
        ? `Public HTTPS ${target.publicExposure.publicBaseUrl} through PK01 Caddy and ${target.id} frpc; no master server forwarding and no Kubernetes Ingress/NodePort/LoadBalancer.`
        : "ClusterIP only; no public ingress or node-level exposure.",
      resourcePolicy: "No Kubernetes CPU/memory requests or limits, matching issue #220.",
      imageVersionControl: "Sub2API image repository/tag/pullPolicy are controlled by config/platform-infra/sub2api.yaml in the UniDesk repository.",
      urlAllowlistControl: "Sub2API upstream URL validation options are controlled by config/platform-infra/sub2api.yaml and rendered to SECURITY_URL_ALLOWLIST_* env vars.",
      networkPolicy: "NetworkPolicy/allow-all is rendered with the deployment so kube-router cannot silently default-deny Sub2API cross-pod traffic.",
      publicExposure: target.publicExposure?.enabled
        ? {
            mode: "pk01-caddy-frp-direct",
            dataPath: `client -> PK01 Caddy -> PK01 frps remotePort -> ${target.id} frpc -> Sub2API`,
            pikanodeRole: "pikapython.com upstream only; api.pikapython.com does not pass through pikanode Express",
            publicBaseUrl: target.publicExposure.publicBaseUrl,
            hostname: target.publicExposure.dns.hostname,
            expectedA: target.publicExposure.dns.expectedA,
          }
        : null,
      egressProxy: target.egressProxy?.enabled
        ? {
            mode: `${target.id} in-cluster HTTP proxy client to the master VPN subscription`,
            service: `${target.egressProxy.serviceName}.${target.namespace}.svc.cluster.local:${target.egressProxy.listenPort}`,
            sourceRef: target.egressProxy.sourceRef,
            applyToSub2Api: target.egressProxy.applyToSub2Api,
            applyToSentinel: target.egressProxy.applyToSentinel,
            valuesPrinted: false,
          }
        : null,
      dataStores: isExternalTarget(target)
        ? [
            target.databaseMode === "external-active" ? "External PostgreSQL active from platform-db/PK01" : "External PostgreSQL pending from platform-db/Pika01",
            target.redisReplicas === 0 ? `${target.id} local Redis 8 ephemeral cache, scaled to zero until activation` : `${target.id} local Redis 8 ephemeral cache`,
          ]
        : ["PostgreSQL 18", "Redis 8"],
      appPoolCaps: {
        databaseMaxOpenConns: 10,
        databaseMaxIdleConns: 2,
        redisPoolSize: 32,
        redisMinIdleConns: 2,
      },
      standbyActivation: target.databaseMode === "external-pending"
        ? {
            target: target.id,
            currentMode: "predeployed-standby",
            enableByYaml: `change target ${target.id} databaseMode to external-active and set appReplicas/redisReplicas to 1, then apply --target ${target.id} --confirm`,
            sharedExternalDb: `${sub2api.runtime.database.host}:${sub2api.runtime.database.port}/${sub2api.runtime.database.dbName}`,
            sentinelEnabled: targetHasSentinel(sub2api, target),
          }
        : null,
      cleanup: managedResourceCleanupPlan(sub2api, target),
    },
    policy,
    next: {
      dryRun: `bun scripts/cli.ts platform-infra sub2api apply --target ${target.id} --dry-run`,
      apply: target.databaseMode === "external-pending" && target.appReplicas === 0
        ? `bun scripts/cli.ts platform-infra sub2api apply --target ${target.id} --confirm # predeploy only; app replicas=0 until DB is ready`
        : `bun scripts/cli.ts platform-infra sub2api apply --target ${target.id} --confirm`,
      status: `bun scripts/cli.ts platform-infra sub2api status --target ${target.id}`,
      validate: `bun scripts/cli.ts platform-infra sub2api validate --target ${target.id}`,
    },
  };
}

async function apply(config: UniDeskConfig, options: ApplyOptions): Promise<Record<string, unknown>> {
  const sub2api = readSub2ApiConfig();
  const target = resolveTarget(sub2api, options.targetId);
  const yaml = manifest(sub2api, target);
  const policy = policyChecks(sub2api, yaml, target);
  if (!policy.every((check) => check.ok)) {
    return {
      ok: false,
      action: "platform-infra-sub2api-apply",
      mode: "policy-blocked",
      target: target.id,
      policy,
    };
  }
  if (options.confirm && !options.wait) {
    const job = startJob(
      `platform_infra_sub2api_apply_${target.id.toLowerCase()}`,
      ["bun", "scripts/cli.ts", "platform-infra", "sub2api", "apply", "--target", target.id, "--confirm", "--wait"],
      `Apply ${target.id} k3s platform-infra Sub2API manifests through the controlled UniDesk CLI`,
    );
    return {
      ok: true,
      action: "platform-infra-sub2api-apply",
      mode: "async-job",
      target: {
        id: target.id,
        route: target.route,
        namespace: target.namespace,
      },
      job,
      statusCommand: `bun scripts/cli.ts job status ${job.id} --tail-bytes 12000`,
      next: {
        status: `bun scripts/cli.ts job status ${job.id} --tail-bytes 12000`,
        rollout: `bun scripts/cli.ts platform-infra sub2api status --target ${target.id}`,
        validate: `bun scripts/cli.ts platform-infra sub2api validate --target ${target.id}`,
      },
    };
  }
  if (options.dryRun) {
    const result = await capture(config, target.route, ["sh"], dryRunScript(yaml, target));
    const parsed = parseJsonOutput(result.stdout);
    return {
      ok: result.exitCode === 0 && boolField(parsed, "ok", false),
      action: "platform-infra-sub2api-apply",
      mode: "dry-run",
      target: {
        id: target.id,
        route: target.route,
        namespace: target.namespace,
      },
      policy,
      remote: parsed ?? compactCapture(result, { full: true }),
    };
  }
  const secretMaterial = target.databaseMode === "external-active" ? prepareExternalActiveSecret(sub2api) : null;
  const publicExposureSecretMaterial = preparePublicExposureSecret(sub2api, target);
  const egressProxySecretMaterial = prepareEgressProxySecret(sub2api, target);
  const result = await capture(config, target.route, ["sh"], applyScript(sub2api, yaml, target, secretMaterial, publicExposureSecretMaterial, egressProxySecretMaterial));
  const parsed = parseJsonOutput(result.stdout);
  const pk01Exposure = publicExposureSecretMaterial === null ? null : await applyPk01PublicExposure(config, target);
  return {
    ok: result.exitCode === 0 && boolField(parsed, "ok", false) && (pk01Exposure === null || pk01Exposure.ok === true),
    action: "platform-infra-sub2api-apply",
    mode: "confirmed",
    target: {
      id: target.id,
      route: target.route,
      namespace: target.namespace,
    },
    policy,
    remote: parsed ?? compactCapture(result, { full: true }),
    pk01Exposure,
    next: {
      status: `bun scripts/cli.ts platform-infra sub2api status --target ${target.id}`,
      validate: `bun scripts/cli.ts platform-infra sub2api validate --target ${target.id}`,
    },
  };
}

async function status(config: UniDeskConfig, options: DisclosureOptions): Promise<Record<string, unknown>> {
  const sub2api = readSub2ApiConfig();
  const target = resolveTarget(sub2api, options.targetId);
  const result = await capture(config, target.route, ["sh"], statusScript(sub2api, target));
  const parsed = parseJsonOutput(result.stdout);
  if (options.raw) {
    return {
      ok: result.exitCode === 0 && boolField(parsed, "ok", false),
      action: "platform-infra-sub2api-status",
      target: {
        id: target.id,
        route: target.route,
        namespace: target.namespace,
      },
      remote: compactCapture(result, { full: true }),
      parsed,
    };
  }
  return {
    ok: result.exitCode === 0 && boolField(parsed, "ok", false),
    action: "platform-infra-sub2api-status",
    target: {
      id: target.id,
      route: target.route,
      namespace: target.namespace,
    },
    summary: parsed,
    remote: compactCapture(result, { full: options.full || result.exitCode !== 0 }),
  };
}

async function validate(config: UniDeskConfig, options: DisclosureOptions): Promise<Record<string, unknown>> {
  const sub2api = readSub2ApiConfig();
  const target = resolveTarget(sub2api, options.targetId);
  const script = target.databaseMode === "external-pending"
    ? validateExternalPendingScript(sub2api, target)
    : target.databaseMode === "external-active"
      ? validateExternalActiveScript(sub2api, target)
    : validateScript(sub2api, target);
  const result = await capture(config, target.route, ["sh"], script);
  const parsed = parseJsonOutput(result.stdout);
  if (options.raw) {
    return {
      ok: result.exitCode === 0 && boolField(parsed, "ok", false),
      action: "platform-infra-sub2api-validate",
      target: {
        id: target.id,
        route: target.route,
        namespace: target.namespace,
      },
      remote: compactCapture(result, { full: true }),
      parsed,
    };
  }
  return {
    ok: result.exitCode === 0 && boolField(parsed, "ok", false),
    action: "platform-infra-sub2api-validate",
    target: {
      id: target.id,
      route: target.route,
      namespace: target.namespace,
    },
    summary: parsed,
    remote: compactCapture(result, { full: options.full || result.exitCode !== 0 }),
  };
}

function policyChecks(sub2api: Sub2ApiConfig, yaml: string, target: Sub2ApiTargetConfig): PolicyCheck[] {
  const cleanup = sub2api.defaults.cleanup;
  const redisService = sub2api.runtime.redis.serviceName;
  const checks: PolicyCheck[] = [
    {
      name: "no-ingress",
      ok: !/^\s*kind:\s*Ingress\s*$/mu.test(yaml),
      detail: "Sub2API must not be exposed through Kubernetes Ingress.",
    },
    {
      name: "no-nodeport-or-loadbalancer",
      ok: !/^\s*type:\s*(NodePort|LoadBalancer)\s*$/mu.test(yaml),
      detail: "Services must remain ClusterIP/internal-only.",
    },
    {
      name: "no-host-network",
      ok: !/^\s*hostNetwork:\s*true\s*$/mu.test(yaml),
      detail: "Pods must not join the host network.",
    },
    {
      name: "no-host-port",
      ok: !/^\s*hostPort:\s*[0-9]+\s*$/mu.test(yaml),
      detail: "Pods must not expose host ports.",
    },
    {
      name: "no-cpu-memory-resources",
      ok: !/^\s*(cpu|memory):\s*/mu.test(yaml),
      detail: "Issue #220 requires no Kubernetes CPU/memory requests or limits.",
    },
    {
      name: "no-resource-quota-or-limit-range",
      ok: !/^\s*kind:\s*(ResourceQuota|LimitRange)\s*$/mu.test(yaml),
      detail: "The platform-infra namespace must not receive quota/default limit objects for this deployment.",
    },
    {
      name: "expected-namespace",
      ok: new RegExp(`^\\s*name:\\s*${escapeRegExp(target.namespace)}\\s*$`, "mu").test(yaml),
      detail: `Manifest declares namespace ${target.namespace}.`,
    },
    {
      name: "allow-all-network-policy",
      ok: hasAllowAllNetworkPolicy(yaml, target.namespace),
      detail: `Manifest must include NetworkPolicy/allow-all in ${target.namespace} to keep kube-router from blocking Sub2API cross-pod traffic.`,
    },
  ];

  if (isExternalTarget(target)) {
    checks.push(
      {
        name: "external-db-no-local-postgres",
        ok: !/^\s*kind:\s*StatefulSet\s*$/mu.test(yaml) && !new RegExp(`\\b${escapeRegExp(cleanup.externalDbState.postgresStatefulSetName)}\\b`, "u").test(yaml),
        detail: "External DB targets must not deploy a local PostgreSQL StatefulSet, Service, or PVC.",
      });
  }

  if (target.databaseMode === "external-pending") {
    checks.push(
      {
        name: "pending-db-replicas-match-yaml",
        ok: hasDeploymentReplicas(yaml, serviceName, target.appReplicas) && hasDeploymentReplicas(yaml, redisService, target.redisReplicas),
        detail: `External-pending predeployment renders YAML-declared app/Redis replicas ${target.appReplicas}/${target.redisReplicas}.`,
      },
    );
  } else if (target.databaseMode === "external-active") {
    checks.push({
      name: "external-active-replicas-match-yaml",
      ok: hasDeploymentReplicas(yaml, serviceName, target.appReplicas) && hasDeploymentReplicas(yaml, redisService, target.redisReplicas),
      detail: `External-active targets render YAML-declared app/Redis replicas ${target.appReplicas}/${target.redisReplicas} against the external PostgreSQL runtime.`,
    });
  } else {
    checks.push({
      name: "bundled-db-present",
      ok: /^\s*kind:\s*StatefulSet\s*$/mu.test(yaml) && new RegExp(`\\b${escapeRegExp(cleanup.externalDbState.postgresStatefulSetName)}\\b`, "u").test(yaml),
      detail: "Bundled active targets render the local PostgreSQL StatefulSet.",
    });
  }

  if (target.redisMode === "local-ephemeral") {
    checks.push({
      name: "local-redis-ephemeral",
      ok: !new RegExp(`\\b${escapeRegExp(cleanup.redisPersistentState.pvcName)}\\b`, "u").test(yaml) && /^\s*emptyDir:\s*\{\}\s*$/mu.test(yaml),
      detail: "Local Redis is an ephemeral cache and must not allocate persistent Redis storage.",
    });
  }

  if (target.egressProxy?.enabled) {
    checks.push({
      name: "egress-proxy-yaml-controlled",
      ok: hasDeploymentReplicas(yaml, target.egressProxy.deploymentName, 1) && new RegExp(`^\\s*name:\\s*${escapeRegExp(target.egressProxy.serviceName)}\\s*$`, "mu").test(yaml),
      detail: "Egress HTTP proxy client must be rendered as a YAML-controlled platform-infra Deployment and ClusterIP Service.",
    });
  }

  return checks;
}

function hasAllowAllNetworkPolicy(yaml: string, namespaceName: string): boolean {
  return yaml.split(/^---\s*$/mu).some((document) => {
    return /^\s*kind:\s*NetworkPolicy\s*$/mu.test(document)
      && /^\s*name:\s*allow-all\s*$/mu.test(document)
      && new RegExp(`^\\s*namespace:\\s*${escapeRegExp(namespaceName)}\\s*$`, "mu").test(document)
      && /^\s*podSelector:\s*\{\}\s*$/mu.test(document)
      && /^\s*-\s*Ingress\s*$/mu.test(document)
      && /^\s*-\s*Egress\s*$/mu.test(document)
      && /^\s*ingress:\s*\n\s*-\s*\{\}\s*$/mu.test(document)
      && /^\s*egress:\s*\n\s*-\s*\{\}\s*$/mu.test(document);
  });
}

function hasDeploymentReplicas(yaml: string, name: string, replicas: number): boolean {
  return yaml.split(/^---\s*$/mu).some((document) => {
    return /^\s*kind:\s*Deployment\s*$/mu.test(document)
      && new RegExp(`^\\s*name:\\s*${escapeRegExp(name)}\\s*$`, "mu").test(document)
      && new RegExp(`^\\s*replicas:\\s*${replicas}\\s*$`, "mu").test(document);
  });
}

function escapeRegExp(value: string): string {
  return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
}

function prepareExternalActiveSecret(sub2api: Sub2ApiConfig): ExternalActiveSecretMaterial {
  const database = sub2api.runtime.database;
  const root = secretRoot(sub2api);
  const dbSource = readEnvSourceFile({
    root,
    sourceRef: database.sourceRef,
    missingMessage: (sourcePath) => `external-active requires ${redactRepoPath(sourcePath)}; run platform-db postgres apply/status first to materialize the PK01 DB credential source`,
  });
  const dbValues = dbSource.values;
  const dbUser = requiredEnvValue(dbValues, database.sourceKeys.user, database.sourceRef);
  const dbPassword = requiredEnvValue(dbValues, database.sourceKeys.password, database.sourceRef);
  const dbName = requiredEnvValue(dbValues, database.sourceKeys.dbName, database.sourceRef);
  if (dbUser !== database.user) throw new Error(`${database.sourceRef}.${database.sourceKeys.user} does not match ${configPath}.runtime.database.user`);
  if (dbName !== database.dbName) throw new Error(`${database.sourceRef}.${database.sourceKeys.dbName} does not match ${configPath}.runtime.database.dbName`);

  const appSourcePath = join(root, sub2api.runtime.secrets.appSourceRef);
  const existedBefore = existsSync(appSourcePath);
  const existing = existedBefore ? parseEnvFile(readFileSync(appSourcePath, "utf8")) : {};
  const next = { ...existing };
  next.POSTGRES_PASSWORD = dbPassword;
  if (next.ADMIN_PASSWORD === undefined || next.ADMIN_PASSWORD.length === 0) next.ADMIN_PASSWORD = randomBytes(16).toString("hex");
  if (next.JWT_SECRET === undefined || next.JWT_SECRET.length === 0) next.JWT_SECRET = randomBytes(32).toString("hex");
  if (next.TOTP_ENCRYPTION_KEY === undefined || next.TOTP_ENCRYPTION_KEY.length === 0) next.TOTP_ENCRYPTION_KEY = randomBytes(32).toString("hex");
  const values: Record<typeof requiredSecretKeys[number], string> = {
    POSTGRES_PASSWORD: next.POSTGRES_PASSWORD,
    ADMIN_PASSWORD: next.ADMIN_PASSWORD,
    JWT_SECRET: next.JWT_SECRET,
    TOTP_ENCRYPTION_KEY: next.TOTP_ENCRYPTION_KEY,
  };
  const missing = requiredSecretKeys.filter((key) => values[key].length === 0);
  if (missing.length > 0) throw new Error(`external-active app secret source is missing ${missing.join(", ")}`);
  const action = !existedBefore
    ? "create"
    : requiredSecretKeys.some((key) => existing[key] !== values[key])
      ? "update"
      : "none";
  if (action !== "none") writeEnvFile(appSourcePath, { ...existing, ...values });
  return {
    sourceRef: database.sourceRef,
    sourcePath: dbSource.sourcePathRedacted,
    appSourceRef: sub2api.runtime.secrets.appSourceRef,
    appSourcePath: redactRepoPath(appSourcePath),
    action,
    fingerprint: fingerprintSecretValues(values, [...requiredSecretKeys]),
    values,
  };
}

function preparePublicExposureSecret(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): PublicExposureSecretMaterial | null {
  const exposure = target.publicExposure;
  if (exposure === null || !exposure.enabled) return null;
  return prepareFrpcSecret({
    secretRoot: secretRoot(sub2api),
    exposure,
    sourcePathRedactor: redactRepoPath,
    parseEnvFile,
    requiredEnvValue,
    readTextFile: (sourcePath) => {
      if (!existsSync(sourcePath)) throw new Error(`publicExposure requires ${redactRepoPath(sourcePath)} with ${exposure.frpc.tokenSourceKey}; copy the PK01 frps token into the local secret source first`);
      return readTextFile(sourcePath);
    },
  });
}

function prepareEgressProxySecret(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): EgressProxySecretMaterial | null {
  const proxy = target.egressProxy;
  if (proxy === null || !proxy.enabled) return null;
  const source = readEnvSourceFile({
    root: secretRoot(sub2api),
    sourceRef: proxy.sourceRef,
    missingMessage: (sourcePath) => `egressProxy requires ${redactRepoPath(sourcePath)} with ${proxy.sourceKey}; materialize the master VPN subscription source first`,
  });
  const values = source.values;
  const subscriptionUrl = requiredEnvValue(values, proxy.sourceKey, proxy.sourceRef);
  const subscription = fetchSubscription(subscriptionUrl);
  const decoded = decodeSubscription(subscription.body);
  const nodes = decoded.split(/\r?\n/gu).map((line) => line.trim()).filter(Boolean);
  const selected = selectSubscriptionNode(nodes, proxy.preferredOutbound);
  const configJson = renderSingBoxConfig(selected, proxy);
  const proxyUrl = `http://${proxy.serviceName}.${target.namespace}.svc.cluster.local:${proxy.listenPort}`;
  const noProxy = proxy.noProxy.join(",");
  return {
    sourceRef: proxy.sourceRef,
    sourcePath: source.sourcePathRedacted,
    secretName: proxy.secretName,
    secretKey: proxy.secretKey,
    fingerprint: fingerprintSecretValues({ subscription: subscription.body, configJson }, ["subscription", "configJson"]),
    subscriptionBytes: Buffer.byteLength(subscription.body, "utf8"),
    selectedOutbound: selected.kind,
    configJson,
    proxyUrl,
    noProxy,
    valuesPrinted: false,
  };
}

function fetchSubscription(subscriptionUrl: string): { body: string } {
  const shellUrl = shQuote(subscriptionUrl);
  const command = `curl -fsSL --connect-timeout 10 --max-time 30 ${shellUrl}`;
  const proc = Bun.spawnSync(["bash", "-lc", command], { stdout: "pipe", stderr: "pipe" });
  if (proc.exitCode !== 0) {
    const stderr = new TextDecoder().decode(proc.stderr).slice(-500);
    throw new Error(`failed to fetch master VPN subscription: exit=${proc.exitCode} stderr=${stderr}`);
  }
  const body = new TextDecoder().decode(proc.stdout).trim();
  if (body.length === 0) throw new Error("master VPN subscription is empty");
  return { body };
}

function decodeSubscription(raw: string): string {
  if (raw.includes("://")) return raw;
  const normalized = raw.replace(/\s+/gu, "");
  const padding = "=".repeat((4 - (normalized.length % 4)) % 4);
  try {
    return Buffer.from(`${normalized}${padding}`, "base64").toString("utf8");
  } catch (error) {
    throw new Error(`master VPN subscription is neither URI list nor base64 URI list: ${String(error)}`);
  }
}

type SubscriptionNode =
  | { kind: "vless-reality"; uri: string; uuid: string; host: string; port: number; sni: string; flow: string | null; fingerprint: string | null; publicKey: string; shortId: string | null }
  | { kind: "hysteria2"; uri: string; password: string; host: string; port: number; sni: string | null; obfsPassword: string | null; insecure: boolean };

function selectSubscriptionNode(nodes: string[], preferred: Sub2ApiEgressProxyConfig["preferredOutbound"]): SubscriptionNode {
  const parsed = nodes.map(parseSubscriptionNode).filter((node): node is SubscriptionNode => node !== null);
  const preferredNode = parsed.find((node) => node.kind === preferred);
  if (preferredNode !== undefined) return preferredNode;
  const fallback = parsed.find((node) => node.kind === "vless-reality") ?? parsed.find((node) => node.kind === "hysteria2");
  if (fallback !== undefined) return fallback;
  throw new Error("master VPN subscription does not contain a supported vless-reality or hysteria2 node");
}

function parseSubscriptionNode(uri: string): SubscriptionNode | null {
  let url: URL;
  try {
    url = new URL(uri);
  } catch {
    return null;
  }
  if (url.protocol === "vless:") {
    const params = url.searchParams;
    if (params.get("security") !== "reality") return null;
    const publicKey = params.get("pbk");
    if (publicKey === null || publicKey.length === 0) return null;
    return {
      kind: "vless-reality",
      uri,
      uuid: decodeURIComponent(url.username),
      host: requiredUrlHost(url, uri),
      port: requiredUrlPort(url, uri),
      sni: params.get("sni") ?? "",
      flow: params.get("flow"),
      fingerprint: params.get("fp"),
      publicKey,
      shortId: params.get("sid"),
    };
  }
  if (url.protocol === "hysteria2:" || url.protocol === "hy2:") {
    const params = url.searchParams;
    return {
      kind: "hysteria2",
      uri,
      password: decodeURIComponent(url.username),
      host: requiredUrlHost(url, uri),
      port: requiredUrlPort(url, uri),
      sni: params.get("sni"),
      obfsPassword: params.get("obfs-password"),
      insecure: params.get("insecure") === "1" || params.get("insecure") === "true",
    };
  }
  return null;
}

function requiredUrlHost(url: URL, uri: string): string {
  if (url.hostname.length === 0) throw new Error(`VPN subscription node is missing host: ${redactSubscriptionUri(uri)}`);
  return url.hostname;
}

function requiredUrlPort(url: URL, uri: string): number {
  const port = Number(url.port);
  if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error(`VPN subscription node is missing a valid port: ${redactSubscriptionUri(uri)}`);
  return port;
}

function renderSingBoxConfig(node: SubscriptionNode, proxy: Sub2ApiEgressProxyConfig): string {
  const outbound = node.kind === "vless-reality"
    ? {
        type: "vless",
        tag: "master-vpn",
        server: node.host,
        server_port: node.port,
        uuid: node.uuid,
        flow: node.flow ?? undefined,
        tls: {
          enabled: true,
          server_name: node.sni,
          utls: { enabled: true, fingerprint: node.fingerprint ?? "chrome" },
          reality: { enabled: true, public_key: node.publicKey, short_id: node.shortId ?? "" },
        },
      }
    : {
        type: "hysteria2",
        tag: "master-vpn",
        server: node.host,
        server_port: node.port,
        password: node.password,
        obfs: node.obfsPassword === null ? undefined : { type: "salamander", password: node.obfsPassword },
        tls: { enabled: true, server_name: node.sni ?? node.host, insecure: node.insecure },
      };
  const config = stripUndefined({
    log: { level: "info", timestamp: true },
    inbounds: [
      {
        type: "mixed",
        tag: "mixed-in",
        listen: "0.0.0.0",
        listen_port: proxy.listenPort,
      },
    ],
    outbounds: [
      outbound,
      { type: "direct", tag: "direct" },
      { type: "block", tag: "block" },
    ],
    route: {
      rules: [
        { ip_is_private: true, outbound: "direct" },
        { domain_suffix: ["cluster.local", "svc"], outbound: "direct" },
      ],
      final: "master-vpn",
    },
  });
  return `${JSON.stringify(config, null, 2)}\n`;
}

function stripUndefined(value: unknown): unknown {
  if (Array.isArray(value)) return value.map(stripUndefined);
  if (value !== null && typeof value === "object") {
    const output: Record<string, unknown> = {};
    for (const [key, child] of Object.entries(value as Record<string, unknown>)) {
      if (child !== undefined) output[key] = stripUndefined(child);
    }
    return output;
  }
  return value;
}

function redactSubscriptionUri(uri: string): string {
  return uri.replace(/\/\/[^@]+@/u, "//<redacted>@").replace(/password=[^&#]+/giu, "password=<redacted>").replace(/pbk=[^&#]+/giu, "pbk=<redacted>");
}

async function applyPk01PublicExposure(config: UniDeskConfig, target: Sub2ApiTargetConfig): Promise<Record<string, unknown>> {
  const exposure = target.publicExposure;
  if (exposure === null || !exposure.enabled) return { ok: true, action: "not-enabled" };
  const start = await startPk01PublicExposureJob(config, target, exposure);
  if (!start.ok || typeof start.remoteJobId !== "string") {
    return {
      ok: false,
      action: "platform-infra-sub2api-pk01-public-exposure",
      route: exposure.pk01.route,
      mode: "remote-job-start-failed",
      remoteJob: start,
    };
  }
  const waited = await waitPk01PublicExposureJob(config, exposure, start.remoteJobId);
  const terminal = asRecordOrNull(waited.terminal);
  const summary = asRecordOrNull(terminal?.summary);
  return {
    ok: waited.ok === true && boolField(summary, "ok", false),
    action: "platform-infra-sub2api-pk01-public-exposure",
    route: exposure.pk01.route,
    mode: "remote-job",
    summary,
    remoteJob: {
      start,
      waited,
    },
  };
}

async function startPk01PublicExposureJob(config: UniDeskConfig, target: Sub2ApiTargetConfig, exposure: Sub2ApiPublicExposureConfig): Promise<Record<string, unknown>> {
  const jobId = `sub2api-pk01-exposure-${new Date().toISOString().replace(/[^0-9A-Za-z]/gu, "")}-${randomBytes(3).toString("hex")}`;
  const payload = pk01PublicExposureScript(target, exposure);
  const payloadB64 = Buffer.from(payload, "utf8").toString("base64");
  const script = `
set -eu
job_id=${shQuote(jobId)}
base="$HOME/.unidesk/platform-infra/sub2api-pk01-exposure/jobs"
job_dir="$base/$job_id"
mkdir -p "$job_dir"
payload="$job_dir/payload.sh"
runner="$job_dir/runner.sh"
stdout="$job_dir/stdout.log"
stderr="$job_dir/stderr.log"
state="$job_dir/state.json"
printf '%s' '${payloadB64}' | base64 -d >"$payload"
chmod 0700 "$payload"
cat >"$runner" <<'RUNNER'
#!/bin/sh
set +e
job_dir="$1"
payload="$job_dir/payload.sh"
stdout="$job_dir/stdout.log"
stderr="$job_dir/stderr.log"
state="$job_dir/state.json"
write_state() {
  status="$1"
  stage="$2"
  exit_code="$3"
  python3 - "$state" "$status" "$stage" "$exit_code" <<'PY'
import datetime
import json
import sys

path, status, stage, exit_code = sys.argv[1:5]
payload = {
    "ok": status == "succeeded",
    "status": status,
    "stage": stage,
    "updatedAt": datetime.datetime.now(datetime.timezone.utc).isoformat(),
    "exitCode": None if exit_code == "" else int(exit_code),
}
if status in ("succeeded", "failed"):
    payload["finishedAt"] = payload["updatedAt"]
with open(path, "w", encoding="utf-8") as handle:
    json.dump(payload, handle, ensure_ascii=False)
PY
}
write_state running start ""
sh "$payload" >"$stdout" 2>"$stderr"
rc=$?
if [ "$rc" -eq 0 ]; then
  write_state succeeded complete "$rc"
else
  write_state failed complete "$rc"
fi
exit "$rc"
RUNNER
chmod 0700 "$runner"
python3 - "$state" <<'PY'
import datetime
import json
import sys

payload = {
    "ok": False,
    "status": "queued",
    "stage": "queued",
    "updatedAt": datetime.datetime.now(datetime.timezone.utc).isoformat(),
    "exitCode": None,
}
with open(sys.argv[1], "w", encoding="utf-8") as handle:
    json.dump(payload, handle, ensure_ascii=False)
PY
nohup "$runner" "$job_dir" >/dev/null 2>&1 &
printf '%s' "$!" >"$job_dir/pid"
python3 - "$job_id" "$job_dir" <<'PY'
import json
import os
import sys

job_id, job_dir = sys.argv[1:3]
payload = {
    "ok": True,
    "remoteJobId": job_id,
    "statePath": os.path.join(job_dir, "state.json"),
    "stdoutPath": os.path.join(job_dir, "stdout.log"),
    "stderrPath": os.path.join(job_dir, "stderr.log"),
    "valuesPrinted": False,
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
PY
`;
  const result = await capture(config, exposure.pk01.route, ["sh"], script);
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && boolField(parsed, "ok", false),
    remoteJobId: typeof parsed?.remoteJobId === "string" ? parsed.remoteJobId : null,
    parsed,
    capture: compactCapture(result, { full: result.exitCode !== 0 }),
  };
}

async function waitPk01PublicExposureJob(config: UniDeskConfig, exposure: Sub2ApiPublicExposureConfig, remoteJobId: string): Promise<Record<string, unknown>> {
  const observations: Array<Record<string, unknown>> = [];
  const maxPolls = 120;
  let lastProgressKey: string | null = null;
  for (let attempt = 0; attempt < maxPolls; attempt += 1) {
    const observation = await readPk01PublicExposureJob(config, exposure, remoteJobId);
    observations.push(observation.summary);
    const statusValue = observation.status;
    const stage = typeof observation.summary.stage === "string" ? observation.summary.stage : null;
    const progressKey = `${statusValue ?? "unknown"}:${stage ?? "unknown"}`;
    if (attempt === 0 || progressKey !== lastProgressKey || attempt % 6 === 0 || statusValue === "succeeded" || statusValue === "failed") {
      lastProgressKey = progressKey;
      console.error(JSON.stringify({
        event: "platform-infra.sub2api.pk01-exposure.progress",
        at: new Date().toISOString(),
        remoteJobId,
        attempt: attempt + 1,
        status: statusValue,
        stage,
        exitCode: observation.summary.exitCode ?? null,
      }));
    }
    if (statusValue === "succeeded" || statusValue === "failed") {
      return {
        ok: statusValue === "succeeded" && boolField(asRecordOrNull(observation.summary.summary), "ok", false),
        attempts: attempt + 1,
        terminal: observation.summary,
        recent: observations.slice(-10),
      };
    }
    await Bun.sleep(5000);
  }
  return {
    ok: false,
    attempts: maxPolls,
    terminal: null,
    recent: observations.slice(-10),
    error: "PK01 public exposure job did not finish before local polling budget",
  };
}

async function readPk01PublicExposureJob(config: UniDeskConfig, exposure: Sub2ApiPublicExposureConfig, remoteJobId: string): Promise<{ status: string | null; summary: Record<string, unknown> }> {
  const safeId = remoteJobId.replace(/[^A-Za-z0-9_.-]/gu, "");
  const script = `
set +e
job_dir="$HOME/.unidesk/platform-infra/sub2api-pk01-exposure/jobs/${safeId}"
state="$job_dir/state.json"
stdout="$job_dir/stdout.log"
stderr="$job_dir/stderr.log"
if [ -f "$state" ]; then cat "$state"; else printf '{"status":"missing","stage":"missing","exitCode":null}'; fi
printf '\\n---STDOUT---\\n'
if [ -f "$stdout" ]; then tail -200 "$stdout"; fi
printf '\\n---STDERR---\\n'
if [ -f "$stderr" ]; then tail -120 "$stderr"; fi
printf '\\n---DOWNLOAD---\\n'
download_part="$HOME/.cache/unidesk/platform-infra/caddy-linux-amd64.part"
download_cache="$HOME/.cache/unidesk/platform-infra/caddy-linux-amd64"
if [ -f "$download_part" ]; then stat -c 'part_bytes=%s part_mtime=%y' "$download_part"; fi
if [ -f "$download_cache" ]; then stat -c 'cache_bytes=%s cache_mtime=%y' "$download_cache"; fi
`;
  const result = await capture(config, exposure.pk01.route, ["sh"], script);
  const [stateText, rest = ""] = result.stdout.split("\n---STDOUT---\n");
  const [stdoutAndMaybeStderr = "", downloadProgress = ""] = rest.split("\n---DOWNLOAD---\n");
  const [stdoutTail = "", stderrTail = ""] = stdoutAndMaybeStderr.split("\n---STDERR---\n");
  const parsed = parseJsonOutput(stateText) ?? {};
  const statusValue = typeof parsed.status === "string" ? parsed.status : null;
  const summary = parseJsonOutput(stdoutTail);
  return {
    status: statusValue,
    summary: {
      ok: result.exitCode === 0,
      remoteJobId,
      status: statusValue,
      stage: parsed.stage ?? null,
      updatedAt: parsed.updatedAt ?? null,
      finishedAt: parsed.finishedAt ?? null,
      exitCode: parsed.exitCode ?? null,
      summary,
      stdoutTail: stdoutTail.slice(-8000),
      stderrTail: stderrTail.slice(-4000),
      downloadProgress: downloadProgress.slice(-1000),
      capture: compactCapture(result, { full: result.exitCode !== 0 }),
    },
  };
}

function pk01PublicExposureScript(target: Sub2ApiTargetConfig, exposure: Sub2ApiPublicExposureConfig): string {
  const caddyfile = renderPk01Caddyfile(exposure);
  const serviceUnit = renderPk01CaddyService(exposure);
  const caddyfileB64 = Buffer.from(caddyfile, "utf8").toString("base64");
  const serviceUnitB64 = Buffer.from(serviceUnit, "utf8").toString("base64");
  const caddyDownloadProxyArgs = exposure.pk01.caddyDownloadProxyUrl === null ? "" : `--proxy ${shQuote(exposure.pk01.caddyDownloadProxyUrl)}`;
  const caddyDownloadProxyUrl = exposure.pk01.caddyDownloadProxyUrl ?? "";
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
caddyfile="$tmp/Caddyfile"
service_unit="$tmp/${exposure.pk01.caddyServiceName}.service"
printf '%s' '${caddyfileB64}' | base64 -d >"$caddyfile"
printf '%s' '${serviceUnitB64}' | base64 -d >"$service_unit"
download_out="$tmp/download.out"
download_err="$tmp/download.err"
install_out="$tmp/install.out"
install_err="$tmp/install.err"
validate_out="$tmp/validate.out"
validate_err="$tmp/validate.err"
pikanode_out="$tmp/pikanode.out"
pikanode_err="$tmp/pikanode.err"
caddy_out="$tmp/caddy.out"
caddy_err="$tmp/caddy.err"
probe_out="$tmp/probe.out"
probe_err="$tmp/probe.err"
download_action="kept-existing"
download_proxy_url=${shQuote(caddyDownloadProxyUrl)}
download_proxy_mode="direct"
if [ -n "$download_proxy_url" ]; then download_proxy_mode="curl-proxy"; fi
download_rc=0
if ! [ -x ${shQuote(exposure.pk01.caddyBinaryPath)} ]; then
  cache_dir="$HOME/.cache/unidesk/platform-infra"
  cache_path="$cache_dir/caddy-linux-amd64"
  cache_part="$cache_path.part"
  mkdir -p "$cache_dir"
  if [ -x "$cache_path" ]; then
    download_action="used-cache"
    "$cache_path" version >"$download_out" 2>"$download_err" || true
  else
    download_action="downloaded"
    resume_args=
    if [ -s "$cache_part" ]; then resume_args="-C -"; fi
    curl -fL --connect-timeout 20 --retry 5 --retry-delay 3 --max-time 600 ${caddyDownloadProxyArgs} $resume_args ${shQuote(exposure.pk01.caddyDownloadUrl)} -o "$cache_part" >"$download_out" 2>"$download_err"
    download_rc=$?
    if [ "$download_rc" -eq 33 ]; then
      rm -f "$cache_part"
      curl -fL --connect-timeout 20 --retry 5 --retry-delay 3 --max-time 600 ${caddyDownloadProxyArgs} ${shQuote(exposure.pk01.caddyDownloadUrl)} -o "$cache_part" >>"$download_out" 2>>"$download_err"
      download_rc=$?
    fi
    if [ "$download_rc" -eq 0 ]; then
      mv "$cache_part" "$cache_path"
      chmod 0755 "$cache_path"
    fi
  fi
  if [ "$download_rc" -eq 0 ]; then
    sudo install -m 0755 "$cache_path" ${shQuote(exposure.pk01.caddyBinaryPath)} >>"$download_out" 2>>"$download_err"
    download_rc=$?
  fi
else
  rm -f "$HOME/.cache/unidesk/platform-infra/caddy-linux-amd64.part"
  ${shQuote(exposure.pk01.caddyBinaryPath)} version >"$download_out" 2>"$download_err" || true
fi
install_rc=1
if [ "$download_rc" -eq 0 ]; then
  sudo mkdir -p "$(dirname ${shQuote(exposure.pk01.caddyConfigPath)})" ${shQuote(exposure.pk01.caddyStorageDir)} /etc/systemd/system
  merged_caddyfile="$tmp/Caddyfile.merged"
  sudo python3 - "$caddyfile" ${shQuote(exposure.pk01.caddyConfigPath)} "$merged_caddyfile" ${shQuote(exposure.dns.hostname)} >"$install_out" 2>"$install_err" <<'PY'
${pk01CaddyMergeManagedBlocksPython()}
PY
  install_rc=$?
  if [ "$install_rc" -eq 0 ]; then
    sudo install -m 0644 "$merged_caddyfile" ${shQuote(exposure.pk01.caddyConfigPath)} >>"$install_out" 2>>"$install_err"
    install_rc=$?
  fi
  if [ "$install_rc" -eq 0 ]; then
    sudo install -m 0644 "$service_unit" /etc/systemd/system/${exposure.pk01.caddyServiceName}.service >>"$install_out" 2>>"$install_err"
    install_rc=$?
  fi
fi
validate_rc=1
if [ "$install_rc" -eq 0 ]; then
  sudo ${shQuote(exposure.pk01.caddyBinaryPath)} validate --config ${shQuote(exposure.pk01.caddyConfigPath)} >"$validate_out" 2>"$validate_err"
  validate_rc=$?
else
  : >"$validate_out"
  : >"$validate_err"
fi
pikanode_rc=1
if [ "$validate_rc" -eq 0 ]; then
  if docker inspect ${shQuote(exposure.pk01.pikanodeContainerName)} >/dev/null 2>&1; then
    docker rm -f ${shQuote(exposure.pk01.pikanodeContainerName)} >"$pikanode_out" 2>"$pikanode_err"
    pikanode_rc=$?
  else
    : >"$pikanode_out"
    : >"$pikanode_err"
    pikanode_rc=0
  fi
  if [ "$pikanode_rc" -eq 0 ]; then
    docker run -d --name ${shQuote(exposure.pk01.pikanodeContainerName)} \\
      --restart=always \\
      -p 127.0.0.1:${exposure.pk01.pikanodeHttpHostPort}:8888 \\
      -p 22000-22099:22000-22099 \\
      -p 7500:7500 \\
      -v ${shQuote(exposure.pk01.pikanodeRoot)}:/usr/src/app \\
      -v /etc/letsencrypt:/etc/letsencrypt:ro \\
      -w /usr/src/app \\
      ${shQuote(exposure.pk01.pikanodeImage)} \\
      sh init.sh >>"$pikanode_out" 2>>"$pikanode_err"
    pikanode_rc=$?
    if [ "$pikanode_rc" -ne 0 ]; then
      printf '%s\\n' '[rollback] restarting pikanode with previous public 80/443 mapping' >>"$pikanode_err"
      docker rm -f ${shQuote(exposure.pk01.pikanodeContainerName)} >>"$pikanode_out" 2>>"$pikanode_err" || true
      docker run -d --name ${shQuote(exposure.pk01.pikanodeContainerName)} \\
        --restart=always \\
        -p 80:8888 \\
        -p 22000-22099:22000-22099 \\
        -p 443:443 \\
        -p 7500:7500 \\
        -v ${shQuote(exposure.pk01.pikanodeRoot)}:/usr/src/app \\
        -v /etc/letsencrypt:/etc/letsencrypt:ro \\
        -w /usr/src/app \\
        ${shQuote(exposure.pk01.pikanodeImage)} \\
        sh init.sh >>"$pikanode_out" 2>>"$pikanode_err" || true
    fi
  fi
else
  : >"$pikanode_out"
  : >"$pikanode_err"
fi
caddy_rc=1
if [ "$pikanode_rc" -eq 0 ]; then
  sudo systemctl daemon-reload >"$caddy_out" 2>"$caddy_err"
  sudo systemctl enable --now ${shQuote(exposure.pk01.caddyServiceName)} >>"$caddy_out" 2>>"$caddy_err"
  caddy_rc=$?
  if [ "$caddy_rc" -eq 0 ]; then
    sudo systemctl reload ${shQuote(exposure.pk01.caddyServiceName)} >>"$caddy_out" 2>>"$caddy_err" || sudo systemctl restart ${shQuote(exposure.pk01.caddyServiceName)} >>"$caddy_out" 2>>"$caddy_err"
    caddy_rc=$?
  fi
fi
probe_rc=1
if [ "$caddy_rc" -eq 0 ]; then
  {
    printf '[pikanode]\\n'
    curl -kfsS --max-time 10 --resolve pikapython.com:443:127.0.0.1 https://pikapython.com/ -o /dev/null -w 'status=%{http_code}\\n'
    printf '[api-health]\\n'
    curl -kfsS --max-time 10 --resolve ${exposure.dns.hostname}:443:127.0.0.1 ${exposure.publicBaseUrl}/health -o /dev/null -w 'status=%{http_code}\\n' || true
  } >"$probe_out" 2>"$probe_err"
  probe_rc=0
else
  : >"$probe_out"
  : >"$probe_err"
fi
python3 - "$download_rc" "$install_rc" "$validate_rc" "$pikanode_rc" "$caddy_rc" "$probe_rc" "$download_action" "$download_proxy_mode" "$download_proxy_url" "$download_out" "$download_err" "$install_out" "$install_err" "$validate_out" "$validate_err" "$pikanode_out" "$pikanode_err" "$caddy_out" "$caddy_err" "$probe_out" "$probe_err" <<'PY'
import json
import sys

download_rc, install_rc, validate_rc, pikanode_rc, caddy_rc, probe_rc = [int(value) for value in sys.argv[1:7]]
download_action = sys.argv[7]
download_proxy_mode = sys.argv[8]
download_proxy_url = sys.argv[9] or None
paths = sys.argv[10:]

def text(path, limit=4000):
    try:
        return open(path, encoding="utf-8", errors="replace").read()[-limit:]
    except FileNotFoundError:
        return ""

payload = {
    "ok": download_rc == 0 and install_rc == 0 and validate_rc == 0 and pikanode_rc == 0 and caddy_rc == 0,
    "target": "${target.id}",
    "mode": "pk01-caddy-frp-direct",
    "publicBaseUrl": "${exposure.publicBaseUrl}",
    "hostname": "${exposure.dns.hostname}",
    "expectedA": "${exposure.dns.expectedA}",
    "dataPath": "client -> PK01 Caddy -> PK01 frps remotePort -> ${target.id} frpc -> Sub2API",
    "pikanodeRole": "pikapython.com upstream only; api.pikapython.com does not pass through pikanode Express",
    "caddy": {
        "binaryPath": "${exposure.pk01.caddyBinaryPath}",
        "configPath": "${exposure.pk01.caddyConfigPath}",
        "serviceName": "${exposure.pk01.caddyServiceName}",
        "downloadProxy": {"mode": download_proxy_mode, "url": download_proxy_url or None},
    },
    "frp": {
        "server": "${exposure.frpc.serverAddr}:${exposure.frpc.serverPort}",
        "remotePort": ${exposure.frpc.remotePort},
        "proxyName": "${exposure.frpc.proxyName}",
    },
    "steps": {
        "downloadCaddy": {"exitCode": download_rc, "action": download_action, "stdout": text(paths[0]), "stderr": text(paths[1])},
        "installConfig": {"exitCode": install_rc, "stdout": text(paths[2]), "stderr": text(paths[3])},
        "validateCaddyConfig": {"exitCode": validate_rc, "stdout": text(paths[4]), "stderr": text(paths[5])},
        "restartPikanodeLoopback": {"exitCode": pikanode_rc, "stdout": text(paths[6]), "stderr": text(paths[7])},
        "startCaddy": {"exitCode": caddy_rc, "stdout": text(paths[8]), "stderr": text(paths[9])},
        "localProbe": {"exitCode": probe_rc, "stdout": text(paths[10]), "stderr": text(paths[11])},
    },
    "valuesPrinted": False,
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ok"] else 1)
PY
`;
}

function renderPk01Caddyfile(exposure: Sub2ApiPublicExposureConfig): string {
  const apexHost = baseDomain(exposure.dns.hostname);
  const apiBlock = renderCaddyManagedBlock(
    sub2apiCaddyManagedMarker,
    renderSimpleReverseProxyCaddySiteBlock({
      hostname: exposure.dns.hostname,
      upstream: `127.0.0.1:${exposure.frpc.remotePort}`,
      responseHeaderTimeoutSeconds: exposure.pk01.responseHeaderTimeoutSeconds,
    }),
  );
  return `{
  email ${exposure.pk01.caddyEmail}
  storage file_system {
    root ${exposure.pk01.caddyStorageDir}
  }
}

${apexHost}, www.${apexHost} {
  reverse_proxy 127.0.0.1:${exposure.pk01.pikanodeHttpHostPort}
}

${apiBlock.trim()}
`;
}

function renderPk01CaddyService(exposure: Sub2ApiPublicExposureConfig): string {
  return `[Unit]
Description=UniDesk PK01 Caddy edge for PikaPython and Sub2API
After=network-online.target docker.service
Wants=network-online.target

[Service]
Type=simple
ExecStart=${exposure.pk01.caddyBinaryPath} run --environ --config ${exposure.pk01.caddyConfigPath}
ExecReload=${exposure.pk01.caddyBinaryPath} reload --config ${exposure.pk01.caddyConfigPath} --force
Restart=always
RestartSec=3
LimitNOFILE=1048576
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
Environment=XDG_DATA_HOME=${exposure.pk01.caddyStorageDir}
Environment=XDG_CONFIG_HOME=/etc/caddy

[Install]
WantedBy=multi-user.target
`;
}

function baseDomain(hostname: string): string {
  const parts = hostname.split(".");
  return parts.length <= 2 ? hostname : parts.slice(-2).join(".");
}

function secretRoot(sub2api: Sub2ApiConfig): string {
  const root = sub2api.runtime.secrets.root;
  return isAbsolute(root) ? root : rootPath(root);
}

function writeEnvFile(path: string, values: Record<string, string>): void {
  mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
  const lines = Object.keys(values)
    .sort()
    .map((key) => `${key}=${quoteEnv(values[key])}`);
  writeFileSync(path, `${lines.join("\n")}\n`, { encoding: "utf8", mode: 0o600 });
  chmodSync(path, 0o600);
}

function quoteEnv(value: string): string {
  if (/^[A-Za-z0-9_./:@%?&=+-]+$/u.test(value)) return value;
  return `'${value.replaceAll("'", "'\"'\"'")}'`;
}

function dryRunScript(yaml: string, target: Sub2ApiTargetConfig): string {
  const encoded = Buffer.from(yaml, "utf8").toString("base64");
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
manifest="$tmp/sub2api.k8s.yaml"
printf '%s' '${encoded}' | base64 -d > "$manifest"
client_out="$tmp/client.out"
client_err="$tmp/client.err"
server_out="$tmp/server.out"
server_err="$tmp/server.err"
kubectl apply --dry-run=client -f "$manifest" >"$client_out" 2>"$client_err"
client_rc=$?
if kubectl get namespace ${target.namespace} >/dev/null 2>&1; then
  namespace_exists=true
  kubectl apply --server-side --dry-run=server --field-manager=${fieldManager} -f "$manifest" >"$server_out" 2>"$server_err"
  server_rc=$?
else
  namespace_exists=false
  server_rc=0
  printf '%s\\n' 'server dry-run skipped because namespace does not exist yet; first apply creates it before namespaced resources' >"$server_out"
  : >"$server_err"
fi
python3 - "$client_rc" "$server_rc" "$namespace_exists" "$client_out" "$client_err" "$server_out" "$server_err" <<'PY'
import json
import sys
client_rc = int(sys.argv[1])
server_rc = int(sys.argv[2])
namespace_exists = sys.argv[3] == "true"
paths = sys.argv[4:]
def text(path):
    try:
        return open(path, encoding="utf-8").read()
    except FileNotFoundError:
        return ""
payload = {
    "ok": client_rc == 0 and server_rc == 0,
    "target": "${target.id}",
    "namespace": "${target.namespace}",
    "namespaceExistsBeforeDryRun": namespace_exists,
    "clientDryRun": {
        "exitCode": client_rc,
        "stdout": text(paths[0])[-4000:],
        "stderr": text(paths[1])[-4000:],
    },
    "serverDryRun": {
        "exitCode": server_rc,
        "disposition": "executed" if namespace_exists else "skipped-namespace-missing",
        "stdout": text(paths[2])[-4000:],
        "stderr": text(paths[3])[-4000:],
    },
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ok"] else 1)
PY
`;
}

function applyScript(
  sub2api: Sub2ApiConfig,
  yaml: string,
  target: Sub2ApiTargetConfig,
  secretMaterial: ExternalActiveSecretMaterial | null,
  publicExposureSecretMaterial: PublicExposureSecretMaterial | null,
  egressProxySecretMaterial: EgressProxySecretMaterial | null,
): string {
  const encoded = Buffer.from(yaml, "utf8").toString("base64");
  const cleanupPlan = managedResourceCleanupPlan(sub2api, target);
  const appSecretName = sub2api.runtime.database.secretName;
  const publicExposureSecretName = publicExposureSecretMaterial?.secretName ?? sub2api.defaults.cleanup.publicExposure.secretName;
  const publicExposureSecretKey = publicExposureSecretMaterial?.secretKey ?? "frpc.toml";
  const egressProxySecretName = egressProxySecretMaterial?.secretName ?? sub2api.defaults.cleanup.egressProxy.secretName;
  const egressProxySecretKey = egressProxySecretMaterial?.secretKey ?? "config.json";
  if (target.databaseMode === "external-active" && secretMaterial === null) throw new Error("external-active apply requires secret material");
  const externalSecretFiles = secretMaterial === null
    ? ""
    : requiredSecretKeys.map((key) => {
        const value = Buffer.from(secretMaterial.values[key], "utf8").toString("base64");
        return `    printf '%s' '${value}' | base64 -d >"$tmp/secret.${key}"`;
      }).join("\n");
  const secretSourceSummary = secretMaterial === null
    ? "None"
    : `json.loads(${JSON.stringify(JSON.stringify({
        sourceRef: secretMaterial.sourceRef,
        sourcePath: secretMaterial.sourcePath,
        appSourceRef: secretMaterial.appSourceRef,
        appSourcePath: secretMaterial.appSourcePath,
        sourceAction: secretMaterial.action,
        fingerprint: secretMaterial.fingerprint,
        valuesPrinted: false,
      }))})`;
  const exposureSecretFile = publicExposureSecretMaterial === null
    ? ""
    : `    printf '%s' '${Buffer.from(publicExposureSecretMaterial.frpcToml, "utf8").toString("base64")}' | base64 -d >"$tmp/frpc.toml"`;
  const exposureSecretSummary = publicExposureSecretMaterial === null
    ? "None"
    : `json.loads(${JSON.stringify(JSON.stringify({
        sourceRef: publicExposureSecretMaterial.sourceRef,
        sourcePath: publicExposureSecretMaterial.sourcePath,
        secretName: publicExposureSecretMaterial.secretName,
        secretKey: publicExposureSecretMaterial.secretKey,
        fingerprint: publicExposureSecretMaterial.fingerprint,
        valuesPrinted: false,
      }))})`;
  const egressProxySecretFile = egressProxySecretMaterial === null
    ? ""
    : `    printf '%s' '${Buffer.from(egressProxySecretMaterial.configJson, "utf8").toString("base64")}' | base64 -d >"$tmp/egress-proxy-config.json"`;
  const egressProxySecretSummary = egressProxySecretMaterial === null
    ? "None"
    : `json.loads(${JSON.stringify(JSON.stringify({
        sourceRef: egressProxySecretMaterial.sourceRef,
        sourcePath: egressProxySecretMaterial.sourcePath,
        secretName: egressProxySecretMaterial.secretName,
        secretKey: egressProxySecretMaterial.secretKey,
        fingerprint: egressProxySecretMaterial.fingerprint,
        subscriptionBytes: egressProxySecretMaterial.subscriptionBytes,
        selectedOutbound: egressProxySecretMaterial.selectedOutbound,
        proxyUrl: egressProxySecretMaterial.proxyUrl,
        noProxy: egressProxySecretMaterial.noProxy,
        valuesPrinted: false,
      }))})`;
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
manifest="$tmp/sub2api.k8s.yaml"
printf '%s' '${encoded}' | base64 -d > "$manifest"
ns_out="$tmp/ns.out"
ns_err="$tmp/ns.err"
secret_out="$tmp/secret.out"
secret_err="$tmp/secret.err"
exposure_secret_out="$tmp/exposure-secret.out"
exposure_secret_err="$tmp/exposure-secret.err"
egress_secret_out="$tmp/egress-secret.out"
egress_secret_err="$tmp/egress-secret.err"
apply_out="$tmp/apply.out"
apply_err="$tmp/apply.err"
cleanup_out="$tmp/cleanup.out"
cleanup_err="$tmp/cleanup.err"
kubectl create namespace ${target.namespace} --dry-run=client -o yaml | kubectl apply --server-side --force-conflicts --field-manager=${fieldManager} -f - >"$ns_out" 2>"$ns_err"
ns_rc=$?
secret_action="unknown"
secret_rc=0
exposure_secret_action="not-enabled"
exposure_secret_rc=0
egress_secret_action="not-enabled"
egress_secret_rc=0
if [ "$ns_rc" -eq 0 ]; then
  if [ "${target.databaseMode}" = "external-pending" ]; then
    secret_action="external-pending-not-managed"
    : >"$secret_out"
    printf '%s\\n' 'external DB target expects its DB credential Secret from the platform DB handoff; predeploy does not create placeholder secrets' >"$secret_err"
  elif [ "${target.databaseMode}" = "external-active" ]; then
${externalSecretFiles}
    kubectl -n ${target.namespace} create secret generic ${appSecretName} \\
      --from-file=POSTGRES_PASSWORD="$tmp/secret.POSTGRES_PASSWORD" \\
      --from-file=ADMIN_PASSWORD="$tmp/secret.ADMIN_PASSWORD" \\
      --from-file=JWT_SECRET="$tmp/secret.JWT_SECRET" \\
      --from-file=TOTP_ENCRYPTION_KEY="$tmp/secret.TOTP_ENCRYPTION_KEY" \\
      --dry-run=client -o yaml | kubectl apply --server-side --force-conflicts --field-manager=${fieldManager} -f - >"$secret_out" 2>"$secret_err"
    secret_rc=$?
    secret_action="external-active-synced"
  elif kubectl -n ${target.namespace} get secret ${appSecretName} >/dev/null 2>&1; then
    secret_action="kept-existing"
    : >"$secret_out"
    : >"$secret_err"
  else
    rand_hex() {
      bytes="$1"
      if command -v openssl >/dev/null 2>&1; then
        openssl rand -hex "$bytes"
      else
        dd if=/dev/urandom bs="$bytes" count=1 2>/dev/null | od -An -tx1 | tr -d ' \\n'
      fi
    }
    kubectl -n ${target.namespace} create secret generic ${appSecretName} \\
      --from-literal=POSTGRES_PASSWORD="$(rand_hex 32)" \\
      --from-literal=ADMIN_PASSWORD="$(rand_hex 16)" \\
      --from-literal=JWT_SECRET="$(rand_hex 32)" \\
      --from-literal=TOTP_ENCRYPTION_KEY="$(rand_hex 32)" \\
      --dry-run=client -o yaml | kubectl apply --server-side --force-conflicts --field-manager=${fieldManager} -f - >"$secret_out" 2>"$secret_err"
    secret_rc=$?
    secret_action="created"
  fi
  if [ "${publicExposureSecretMaterial === null ? "false" : "true"}" = "true" ]; then
${exposureSecretFile}
    kubectl -n ${target.namespace} create secret generic ${publicExposureSecretName} \\
      --from-file=${publicExposureSecretKey}="$tmp/frpc.toml" \\
      --dry-run=client -o yaml | kubectl apply --server-side --force-conflicts --field-manager=${fieldManager} -f - >"$exposure_secret_out" 2>"$exposure_secret_err"
    exposure_secret_rc=$?
    exposure_secret_action="synced"
  else
    : >"$exposure_secret_out"
    : >"$exposure_secret_err"
  fi
  if [ "${egressProxySecretMaterial === null ? "false" : "true"}" = "true" ]; then
${egressProxySecretFile}
    kubectl -n ${target.namespace} create secret generic ${egressProxySecretName} \\
      --from-file=${egressProxySecretKey}="$tmp/egress-proxy-config.json" \\
      --dry-run=client -o yaml | kubectl apply --server-side --force-conflicts --field-manager=${fieldManager} -f - >"$egress_secret_out" 2>"$egress_secret_err"
    egress_secret_rc=$?
    egress_secret_action="synced"
  else
    : >"$egress_secret_out"
    : >"$egress_secret_err"
  fi
fi
apply_rc=1
if [ "$ns_rc" -eq 0 ] && [ "$secret_rc" -eq 0 ] && [ "$exposure_secret_rc" -eq 0 ] && [ "$egress_secret_rc" -eq 0 ]; then
  kubectl apply --server-side --force-conflicts --field-manager=${fieldManager} -f "$manifest" >"$apply_out" 2>"$apply_err"
  apply_rc=$?
else
  : >"$apply_out"
  printf '%s\\n' 'skipped because namespace, app secret, public exposure secret, or egress proxy secret step failed' >"$apply_err"
fi
cleanup_rc=0
if [ "$apply_rc" -eq 0 ]; then
  python3 - "$cleanup_out" "$cleanup_err" <<'PY'
import json
import subprocess
import sys
import time

out_path, err_path = sys.argv[1:3]
namespace = ${JSON.stringify(target.namespace)}
plan = json.loads(${JSON.stringify(JSON.stringify(cleanupPlan))})

def run(args):
    proc = subprocess.run(["kubectl", "-n", namespace, *args], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    return {
        "args": ["kubectl", "-n", namespace, *args],
        "exitCode": proc.returncode,
        "stdout": proc.stdout.decode("utf-8", errors="replace")[-2000:],
        "stderr": proc.stderr.decode("utf-8", errors="replace")[-2000:],
    }

def delete(kind, name):
    return run(["delete", kind, name, "--ignore-not-found=true", "--wait=false"])

items = []
external_db_state = plan["externalDbState"]
redis_persistent_state = plan["redisPersistentState"]
if external_db_state["enabled"]:
    items.append({"name": "legacy-postgres-statefulset", **delete("statefulset", external_db_state["postgresStatefulSetName"])})
    items.append({"name": "legacy-postgres-service", **delete("service", external_db_state["postgresServiceName"])})
    items.append({"name": "legacy-postgres-pvc", **delete("pvc", external_db_state["postgresPvcName"])})
    items.append({"name": "legacy-app-data-pvc", **delete("pvc", external_db_state["appDataPvcName"])})
if redis_persistent_state["enabled"]:
    items.append({"name": "legacy-redis-pvc", **delete("pvc", redis_persistent_state["pvcName"])})
if not plan["publicExposure"]["enabled"]:
    items.append({"name": "disabled-public-frpc-deployment", **delete("deployment", plan["publicExposure"]["deploymentName"])})
    items.append({"name": "disabled-public-frpc-configmap", **delete("configmap", plan["publicExposure"]["configMapName"])})
    items.append({"name": "disabled-public-frpc-secret", **delete("secret", plan["publicExposure"]["secretName"])})
if not plan["egressProxy"]["enabled"]:
    items.append({"name": "disabled-egress-proxy-deployment", **delete("deployment", plan["egressProxy"]["deploymentName"])})
    items.append({"name": "disabled-egress-proxy-service", **delete("service", plan["egressProxy"]["serviceName"])})
    items.append({"name": "disabled-egress-proxy-secret", **delete("secret", plan["egressProxy"]["secretName"])})
if not plan["sentinel"]["enabled"]:
    items.append({"name": "disabled-sentinel-cronjob", **delete("cronjob", plan["sentinel"]["cronJobName"])})
    items.append({"name": "disabled-sentinel-jobs", **run(["delete", "job", "-l", f"app.kubernetes.io/name={plan['sentinel']['cronJobName']}", "--ignore-not-found=true", "--wait=false"])})
    items.append({"name": "disabled-sentinel-configmap", **delete("configmap", plan["sentinel"]["configMapName"])})
    items.append({"name": "disabled-sentinel-credentials-secret", **delete("secret", plan["sentinel"]["credentialsSecretName"])})
    items.append({"name": "disabled-sentinel-serviceaccount", **delete("serviceaccount", plan["sentinel"]["serviceAccountName"])})
    items.append({"name": "disabled-sentinel-role", **delete("role", plan["sentinel"]["roleName"])})
    items.append({"name": "disabled-sentinel-rolebinding", **delete("rolebinding", plan["sentinel"]["roleBindingName"])})

watch = []
if external_db_state["enabled"]:
    watch.extend([
        ("statefulset", external_db_state["postgresStatefulSetName"]),
        ("service", external_db_state["postgresServiceName"]),
        ("pvc", external_db_state["postgresPvcName"]),
        ("pvc", external_db_state["appDataPvcName"]),
    ])
if redis_persistent_state["enabled"]:
    watch.append(("pvc", redis_persistent_state["pvcName"]))
if not plan["publicExposure"]["enabled"]:
    watch.append(("deployment", plan["publicExposure"]["deploymentName"]))
if not plan["egressProxy"]["enabled"]:
    watch.append(("deployment", plan["egressProxy"]["deploymentName"]))
    watch.append(("service", plan["egressProxy"]["serviceName"]))
if not plan["sentinel"]["enabled"]:
    watch.append(("cronjob", plan["sentinel"]["cronJobName"]))

deadline = time.time() + 90
remaining = []
while True:
    remaining = []
    for kind, name in watch:
        result = run(["get", kind, name])
        if result["exitCode"] == 0:
            remaining.append({"kind": kind, "name": name})
    if not remaining or time.time() >= deadline:
        break
    time.sleep(3)

payload = {
    "ok": all(item["exitCode"] == 0 for item in items) and not remaining,
    "plan": plan,
    "items": items,
    "remainingAfterWait": remaining,
    "valuesPrinted": False,
}
open(out_path, "w", encoding="utf-8").write(json.dumps(payload, ensure_ascii=False, indent=2))
open(err_path, "w", encoding="utf-8").write("")
sys.exit(0 if payload["ok"] else 1)
PY
  cleanup_rc=$?
else
  : >"$cleanup_out"
  printf '%s\\n' 'skipped because apply failed' >"$cleanup_err"
  cleanup_rc=1
fi
python3 - "$ns_rc" "$secret_rc" "$exposure_secret_rc" "$egress_secret_rc" "$apply_rc" "$cleanup_rc" "$secret_action" "$exposure_secret_action" "$egress_secret_action" "$ns_out" "$ns_err" "$secret_out" "$secret_err" "$exposure_secret_out" "$exposure_secret_err" "$egress_secret_out" "$egress_secret_err" "$apply_out" "$apply_err" "$cleanup_out" "$cleanup_err" <<'PY'
import json
import sys
ns_rc = int(sys.argv[1])
secret_rc = int(sys.argv[2])
exposure_secret_rc = int(sys.argv[3])
egress_secret_rc = int(sys.argv[4])
apply_rc = int(sys.argv[5])
cleanup_rc = int(sys.argv[6])
secret_action = sys.argv[7]
exposure_secret_action = sys.argv[8]
egress_secret_action = sys.argv[9]
paths = sys.argv[10:]
def text(path):
    try:
        return open(path, encoding="utf-8").read()
    except FileNotFoundError:
        return ""
def parsed(path):
    try:
        return json.load(open(path, encoding="utf-8"))
    except Exception:
        return None
payload = {
    "ok": ns_rc == 0 and secret_rc == 0 and exposure_secret_rc == 0 and egress_secret_rc == 0 and apply_rc == 0 and cleanup_rc == 0,
    "target": "${target.id}",
    "namespace": "${target.namespace}",
    "databaseMode": "${target.databaseMode}",
    "appReplicas": ${target.appReplicas},
    "redisReplicas": ${target.redisReplicas},
    "secret": {
        "name": "${appSecretName}",
        "action": secret_action,
        "requiredKeys": ${JSON.stringify(requiredSecretKeys)},
        "managedByThisApply": ${target.databaseMode === "external-pending" ? "False" : "True"},
        "externalActiveSource": ${secretSourceSummary},
        "valuesPrinted": False,
    },
    "publicExposure": ${exposureSecretSummary},
    "egressProxy": ${egressProxySecretSummary},
    "steps": {
        "namespace": {"exitCode": ns_rc, "stdout": text(paths[0])[-4000:], "stderr": text(paths[1])[-4000:]},
        "secret": {"exitCode": secret_rc, "stdout": text(paths[2])[-4000:], "stderr": text(paths[3])[-4000:]},
        "publicExposureSecret": {"exitCode": exposure_secret_rc, "action": exposure_secret_action, "stdout": text(paths[4])[-4000:], "stderr": text(paths[5])[-4000:]},
        "egressProxySecret": {"exitCode": egress_secret_rc, "action": egress_secret_action, "stdout": text(paths[6])[-4000:], "stderr": text(paths[7])[-4000:]},
        "apply": {"exitCode": apply_rc, "stdout": text(paths[8])[-8000:], "stderr": text(paths[9])[-4000:]},
        "cleanup": {"exitCode": cleanup_rc, "summary": parsed(paths[10]), "stdout": text(paths[10])[-8000:], "stderr": text(paths[11])[-4000:]},
    },
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ok"] else 1)
PY
`;
}

function statusScript(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): string {
  const expectedImage = imageRef(sub2api, target);
  const expectedUrlAllowlist = sub2api.security.urlAllowlist;
  const externalPending = target.databaseMode === "external-pending";
  const externalActive = target.databaseMode === "external-active";
  const proxy = target.egressProxy?.enabled ? target.egressProxy : null;
  const expectedProxyEnv = sub2ApiProxyEnv(target);
  const cleanupPlan = managedResourceCleanupPlan(sub2api, target);
  const appSecretName = sub2api.runtime.database.secretName;
  const redisService = sub2api.runtime.redis.serviceName;
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
capture_json() {
  name="$1"
  shift
  "$@" -o json >"$tmp/$name.json" 2>"$tmp/$name.err"
  rc=$?
  printf '%s' "$rc" >"$tmp/$name.rc"
}
capture_json ns kubectl get namespace ${target.namespace}
capture_json deployments kubectl -n ${target.namespace} get deployments -l app.kubernetes.io/part-of=platform-infra
capture_json statefulsets kubectl -n ${target.namespace} get statefulsets -l app.kubernetes.io/part-of=platform-infra
capture_json pods kubectl -n ${target.namespace} get pods -l app.kubernetes.io/part-of=platform-infra
capture_json services kubectl -n ${target.namespace} get services -l app.kubernetes.io/part-of=platform-infra
capture_json pvc kubectl -n ${target.namespace} get pvc -l app.kubernetes.io/part-of=platform-infra
capture_json secrets kubectl -n ${target.namespace} get secret ${appSecretName}
capture_json configmap kubectl -n ${target.namespace} get configmap sub2api-config
capture_json networkpolicies kubectl -n ${target.namespace} get networkpolicy
capture_json cronjobs kubectl -n ${target.namespace} get cronjob -l app.kubernetes.io/part-of=platform-infra
capture_json ingresses kubectl -n ${target.namespace} get ingress
capture_json quotas kubectl -n ${target.namespace} get resourcequota
capture_json limitranges kubectl -n ${target.namespace} get limitrange
pod_name="$(kubectl -n ${target.namespace} get pod -l app.kubernetes.io/name=${serviceName},app.kubernetes.io/component=app -o jsonpath='{.items[0].metadata.name}' 2>"$tmp/pod-name.err" || true)"
printf '%s' "$pod_name" >"$tmp/pod-name.txt"
if [ -n "$pod_name" ]; then
  kubectl -n ${target.namespace} exec "$pod_name" -- sh -c 'printf "SECURITY_URL_ALLOWLIST_ENABLED=%s\\n" "$SECURITY_URL_ALLOWLIST_ENABLED"; printf "SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP=%s\\n" "$SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP"; printf "SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS=%s\\n" "$SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS"; printf "SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS=%s\\n" "$SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS"; printf "HTTP_PROXY=%s\\n" "$HTTP_PROXY"; printf "HTTPS_PROXY=%s\\n" "$HTTPS_PROXY"; printf "ALL_PROXY=%s\\n" "$ALL_PROXY"; printf "NO_PROXY=%s\\n" "$NO_PROXY"' >"$tmp/pod-env.out" 2>"$tmp/pod-env.err"
  printf '%s' "$?" >"$tmp/pod-env.rc"
else
  : >"$tmp/pod-env.out"
  printf '%s\\n' 'sub2api app pod not found' >"$tmp/pod-env.err"
  printf '%s' "1" >"$tmp/pod-env.rc"
fi
python3 - "$tmp" <<'PY'
import json
import os
import sys

tmp = sys.argv[1]

def rc(name):
    try:
        return int(open(os.path.join(tmp, f"{name}.rc"), encoding="utf-8").read() or "1")
    except FileNotFoundError:
        return 1

def load(name):
    path = os.path.join(tmp, f"{name}.json")
    if not os.path.exists(path):
        return None
    try:
        return json.load(open(path, encoding="utf-8"))
    except json.JSONDecodeError:
        return None

def items(name):
    data = load(name)
    if not isinstance(data, dict):
        return []
    return data.get("items") or []

def text(name):
    path = os.path.join(tmp, name)
    try:
        return open(path, encoding="utf-8", errors="replace").read()
    except FileNotFoundError:
        return ""

def deployment_summary(item):
    spec = item.get("spec") or {}
    status = item.get("status") or {}
    desired = spec.get("replicas", 1)
    available = status.get("availableReplicas", 0)
    init_containers = ((spec.get("template") or {}).get("spec") or {}).get("initContainers", [])
    containers = ((spec.get("template") or {}).get("spec") or {}).get("containers", [])
    return {
        "name": item["metadata"]["name"],
        "desired": desired,
        "readyReplicas": status.get("readyReplicas", 0),
        "availableReplicas": available,
        "updatedReplicas": status.get("updatedReplicas", 0),
        "ready": available >= desired,
        "images": [c.get("image") for c in containers],
        "initImages": [c.get("image") for c in init_containers],
    }

def statefulset_summary(item):
    spec = item.get("spec") or {}
    status = item.get("status") or {}
    desired = spec.get("replicas", 1)
    ready = status.get("readyReplicas", 0)
    return {
        "name": item["metadata"]["name"],
        "desired": desired,
        "readyReplicas": ready,
        "currentReplicas": status.get("currentReplicas", 0),
        "updatedReplicas": status.get("updatedReplicas", 0),
        "ready": ready >= desired,
        "images": [c.get("image") for c in ((spec.get("template") or {}).get("spec") or {}).get("containers", [])],
    }

def pod_summary(item):
    status = item.get("status") or {}
    container_statuses = status.get("containerStatuses") or []
    return {
        "name": item["metadata"]["name"],
        "phase": status.get("phase"),
        "ready": all((cs.get("ready") is True) for cs in container_statuses) if container_statuses else False,
        "restarts": sum(int(cs.get("restartCount") or 0) for cs in container_statuses),
        "nodeName": (item.get("spec") or {}).get("nodeName"),
        "containers": [
            {
                "name": cs.get("name"),
                "ready": cs.get("ready"),
                "restartCount": cs.get("restartCount"),
                "image": cs.get("image"),
                "state": list((cs.get("state") or {}).keys()),
                "stateDetail": cs.get("state") or {},
            }
            for cs in container_statuses
        ],
        "initContainers": [
            {
                "name": cs.get("name"),
                "ready": cs.get("ready"),
                "restartCount": cs.get("restartCount"),
                "image": cs.get("image"),
                "state": list((cs.get("state") or {}).keys()),
                "stateDetail": cs.get("state") or {},
            }
            for cs in (status.get("initContainerStatuses") or [])
        ],
        "conditions": [
            {
                "type": condition.get("type"),
                "status": condition.get("status"),
                "reason": condition.get("reason"),
                "message": condition.get("message"),
            }
            for condition in status.get("conditions", [])
        ],
    }

def service_summary(item):
    spec = item.get("spec") or {}
    return {
        "name": item["metadata"]["name"],
        "type": spec.get("type", "ClusterIP"),
        "clusterIP": spec.get("clusterIP"),
        "ports": [
            {
                "name": p.get("name"),
                "port": p.get("port"),
                "targetPort": p.get("targetPort"),
                "nodePort": p.get("nodePort"),
            }
            for p in spec.get("ports", [])
        ],
    }

def pvc_summary(item):
    spec = item.get("spec") or {}
    status = item.get("status") or {}
    req = (spec.get("resources") or {}).get("requests") or {}
    return {
        "name": item["metadata"]["name"],
        "phase": status.get("phase"),
        "storageClassName": spec.get("storageClassName"),
        "requestedStorage": req.get("storage"),
    }

def network_policy_summary(item):
    spec = item.get("spec") or {}
    return {
        "name": item["metadata"]["name"],
        "podSelector": spec.get("podSelector"),
        "policyTypes": spec.get("policyTypes") or [],
        "ingress": spec.get("ingress") or [],
        "egress": spec.get("egress") or [],
    }

def is_allow_all_network_policy(item):
    spec = item.get("spec") or {}
    return (
        item.get("metadata", {}).get("name") == "allow-all"
        and spec.get("podSelector") == {}
        and set(spec.get("policyTypes") or []) == {"Ingress", "Egress"}
        and spec.get("ingress") == [{}]
        and spec.get("egress") == [{}]
    )

def resource_findings(kind, collection):
    findings = []
    for item in collection:
        spec = item.get("spec") or {}
        template_spec = ((spec.get("template") or {}).get("spec") or {})
        if template_spec.get("hostNetwork") is True:
            findings.append({"kind": kind, "name": item["metadata"]["name"], "field": "hostNetwork"})
        all_containers = [(container, "containers") for container in template_spec.get("containers", [])] + [(container, "initContainers") for container in template_spec.get("initContainers", [])]
        for container, container_group in all_containers:
            resources = container.get("resources") or {}
            if resources.get("requests"):
                findings.append({"kind": kind, "name": item["metadata"]["name"], "container": container.get("name"), "containerGroup": container_group, "field": "resources.requests"})
            if resources.get("limits"):
                findings.append({"kind": kind, "name": item["metadata"]["name"], "container": container.get("name"), "containerGroup": container_group, "field": "resources.limits"})
            for port in container.get("ports", []):
                if "hostPort" in port:
                    findings.append({"kind": kind, "name": item["metadata"]["name"], "container": container.get("name"), "containerGroup": container_group, "field": "hostPort", "value": port.get("hostPort")})
    return findings

deployments = items("deployments")
statefulsets = items("statefulsets")
services = items("services")
pods = items("pods")
pvcs = items("pvc")
networkpolicies = items("networkpolicies")
cronjobs = items("cronjobs")
secret = load("secrets")
configmap = load("configmap")
configmap_data = (configmap or {}).get("data") or {}
secret_keys = sorted(((secret or {}).get("data") or {}).keys())
missing_secret_keys = [key for key in ${JSON.stringify(requiredSecretKeys)} if key not in secret_keys]
external_pending = ${externalPending ? "True" : "False"}
external_active = ${externalActive ? "True" : "False"}
expected_app_replicas = ${target.appReplicas}
expected_redis_replicas = ${target.redisReplicas}
cleanup_plan = json.loads(${JSON.stringify(JSON.stringify(cleanupPlan))})
external_db_state = cleanup_plan["externalDbState"]
redis_persistent_state = cleanup_plan["redisPersistentState"]
public_exposure_state = cleanup_plan["publicExposure"]
egress_proxy_state = cleanup_plan["egressProxy"]
service_violations = []
for svc in services:
    spec = svc.get("spec") or {}
    if spec.get("type", "ClusterIP") != "ClusterIP":
        service_violations.append({"name": svc["metadata"]["name"], "type": spec.get("type")})
    for port in spec.get("ports", []):
        if "nodePort" in port:
            service_violations.append({"name": svc["metadata"]["name"], "nodePort": port.get("nodePort")})
resource_violations = resource_findings("Deployment", deployments) + resource_findings("StatefulSet", statefulsets)
expected_image = "${expectedImage}"
expected_url_allowlist = json.loads(${JSON.stringify(JSON.stringify(expectedUrlAllowlist))})
sub2api_deployment = next((deployment_summary(item) for item in deployments if item["metadata"]["name"] == "${serviceName}"), None)
redis_deployment = next((deployment_summary(item) for item in deployments if item["metadata"]["name"] == "${redisService}"), None)
sub2api_desired_aligned = sub2api_deployment is not None and sub2api_deployment.get("desired") == expected_app_replicas
redis_desired_aligned = redis_deployment is not None and redis_deployment.get("desired") == expected_redis_replicas
image_aligned = sub2api_deployment is not None and expected_image in sub2api_deployment.get("images", [])
url_allowlist_runtime = {
    "enabled": configmap_data.get("SECURITY_URL_ALLOWLIST_ENABLED"),
    "allowInsecureHttp": configmap_data.get("SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP"),
    "allowPrivateHosts": configmap_data.get("SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS"),
    "upstreamHosts": configmap_data.get("SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS"),
}
pod_env = {}
for line in text("pod-env.out").splitlines():
    if "=" not in line:
        continue
    key, value = line.split("=", 1)
    pod_env[key] = value
url_allowlist_pod_env = {
    "enabled": pod_env.get("SECURITY_URL_ALLOWLIST_ENABLED"),
    "allowInsecureHttp": pod_env.get("SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP"),
    "allowPrivateHosts": pod_env.get("SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS"),
    "upstreamHosts": pod_env.get("SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS"),
}
expected_url_allowlist_strings = {
    "enabled": str(expected_url_allowlist.get("enabled")).lower(),
    "allowInsecureHttp": str(expected_url_allowlist.get("allowInsecureHttp")).lower(),
    "allowPrivateHosts": str(expected_url_allowlist.get("allowPrivateHosts")).lower(),
    "upstreamHosts": ",".join(expected_url_allowlist.get("upstreamHosts") or []),
}
expected_proxy_env = json.loads(${JSON.stringify(JSON.stringify({
    enabled: proxy !== null && proxy.applyToSub2Api,
    httpProxy: expectedProxyEnv.httpProxy,
    noProxy: expectedProxyEnv.noProxy,
    deploymentName: proxy?.deploymentName ?? null,
    serviceName: proxy?.serviceName ?? null,
  }))})
url_allowlist_configmap_aligned = url_allowlist_runtime == expected_url_allowlist_strings
url_allowlist_pod_env_aligned = rc("pod-env") == 0 and url_allowlist_pod_env == expected_url_allowlist_strings
url_allowlist_aligned = url_allowlist_configmap_aligned and (url_allowlist_pod_env_aligned or (external_pending and expected_app_replicas == 0))
proxy_env_runtime = {
    "HTTP_PROXY": pod_env.get("HTTP_PROXY"),
    "HTTPS_PROXY": pod_env.get("HTTPS_PROXY"),
    "ALL_PROXY": pod_env.get("ALL_PROXY"),
    "NO_PROXY": pod_env.get("NO_PROXY"),
}
if expected_proxy_env.get("enabled"):
    proxy_env_aligned = (
        rc("pod-env") == 0
        and proxy_env_runtime.get("HTTP_PROXY") == expected_proxy_env.get("httpProxy")
        and proxy_env_runtime.get("HTTPS_PROXY") == expected_proxy_env.get("httpProxy")
        and proxy_env_runtime.get("ALL_PROXY") == expected_proxy_env.get("httpProxy")
        and proxy_env_runtime.get("NO_PROXY") == expected_proxy_env.get("noProxy")
    )
else:
    proxy_env_aligned = True
allow_all_network_policy = next((item for item in networkpolicies if item.get("metadata", {}).get("name") == "allow-all"), None)
network_policy = {
    "requiredName": "allow-all",
    "exists": allow_all_network_policy is not None,
    "ok": allow_all_network_policy is not None and is_allow_all_network_policy(allow_all_network_policy),
    "policies": [network_policy_summary(item) for item in networkpolicies],
}
boundary = {
    "internalOnly": len(service_violations) == 0 and len(items("ingresses")) == 0,
    "serviceViolations": service_violations,
    "ingressCount": len(items("ingresses")),
    "resourceQuotaCount": len(items("quotas")),
    "limitRangeCount": len(items("limitranges")),
    "resourceViolations": resource_violations,
}
deployment_summaries = [deployment_summary(item) for item in deployments]
statefulset_summaries = [statefulset_summary(item) for item in statefulsets]
workload_ready = all(d["ready"] for d in deployment_summaries) and all(s["ready"] for s in statefulset_summaries)
local_postgres_present = (
    any(item.get("metadata", {}).get("name") == external_db_state["postgresStatefulSetName"] for item in statefulsets)
    or any(item.get("metadata", {}).get("name") == external_db_state["postgresServiceName"] for item in services)
    or any(item.get("metadata", {}).get("name") in [external_db_state["postgresPvcName"], external_db_state["appDataPvcName"]] for item in pvcs)
)
redis_pvc_present = any(item.get("metadata", {}).get("name") == redis_persistent_state["pvcName"] for item in pvcs)
public_exposure_deployment_present = any(item.get("metadata", {}).get("name") == public_exposure_state["deploymentName"] for item in deployments)
egress_proxy_deployment_present = any(item.get("metadata", {}).get("name") == egress_proxy_state["deploymentName"] for item in deployments)
sentinel_cronjob_present = any(item.get("metadata", {}).get("name") == "${codexPoolSentinelResourceNames().cronJobName}" for item in cronjobs)
standby_disabled_resources_ok = not external_pending or (
    not public_exposure_deployment_present
    and not egress_proxy_deployment_present
    and not sentinel_cronjob_present
)
secret_ready = len(missing_secret_keys) == 0
secret_ok = secret_ready or external_pending
if external_pending:
    state_model_ok = (
        not local_postgres_present
        and not redis_pvc_present
        and sub2api_desired_aligned
        and redis_desired_aligned
        and expected_app_replicas == 0
        and expected_redis_replicas == 0
        and standby_disabled_resources_ok
    )
elif external_active:
    state_model_ok = (
        not local_postgres_present
        and not redis_pvc_present
        and sub2api_desired_aligned
        and redis_desired_aligned
        and expected_app_replicas == 1
        and expected_redis_replicas == 1
    )
else:
    state_model_ok = local_postgres_present and sub2api_desired_aligned and redis_desired_aligned
status_label = "pending-external-db" if external_pending else "external-db-active" if external_active else "active"
payload = {
    "ok": rc("ns") == 0 and workload_ready and image_aligned and url_allowlist_aligned and proxy_env_aligned and network_policy["ok"] and boundary["internalOnly"] and len(resource_violations) == 0 and boundary["resourceQuotaCount"] == 0 and boundary["limitRangeCount"] == 0 and secret_ok and state_model_ok,
    "target": "${target.id}",
    "route": "${target.route}",
    "namespace": "${target.namespace}",
    "status": status_label,
    "databaseMode": "${target.databaseMode}",
    "redisMode": "${target.redisMode}",
    "expectedAppReplicas": expected_app_replicas,
    "expectedRedisReplicas": expected_redis_replicas,
    "namespaceExists": rc("ns") == 0,
    "deployments": deployment_summaries,
    "statefulsets": statefulset_summaries,
    "pods": [pod_summary(item) for item in pods],
    "services": [service_summary(item) for item in services],
    "pvcs": [pvc_summary(item) for item in pvcs],
    "networkPolicy": network_policy,
    "secret": {
        "name": "${appSecretName}",
        "exists": rc("secrets") == 0,
        "requiredKeys": ${JSON.stringify(requiredSecretKeys)},
        "missingKeys": missing_secret_keys,
        "ready": secret_ready,
        "requiredForPredeployOk": not external_pending,
        "valuesPrinted": False,
    },
    "stateModel": {
        "localPostgresPresent": local_postgres_present,
        "redisPvcPresent": redis_pvc_present,
        "sub2apiDesiredReplicasAligned": sub2api_desired_aligned,
        "redisDesiredReplicasAligned": redis_desired_aligned,
        "standbyDisabledResourcesOk": standby_disabled_resources_ok,
        "publicExposureDeploymentPresent": public_exposure_deployment_present,
        "egressProxyDeploymentPresent": egress_proxy_deployment_present,
        "sentinelCronJobPresent": sentinel_cronjob_present,
        "ok": state_model_ok,
    },
    "imageControl": {
        "desiredImage": expected_image,
        "configPath": "config/platform-infra/sub2api.yaml",
        "aligned": image_aligned,
        "runningImages": sub2api_deployment.get("images", []) if sub2api_deployment else [],
    },
    "security": {
        "urlAllowlist": {
            "configPath": "config/platform-infra/sub2api.yaml",
            "expected": expected_url_allowlist,
            "runtime": url_allowlist_runtime,
            "podEnv": url_allowlist_pod_env,
            "aligned": url_allowlist_aligned,
            "configMapAligned": url_allowlist_configmap_aligned,
            "podEnvAligned": url_allowlist_pod_env_aligned,
            "podEnvRequired": not (external_pending and expected_app_replicas == 0),
            "configMapExists": rc("configmap") == 0,
            "podEnvProbe": {
                "podName": text("pod-name.txt"),
                "exitCode": rc("pod-env"),
                "stderr": text("pod-env.err")[-1000:],
            },
        }
    },
    "egressProxy": {
        "enabled": expected_proxy_env.get("enabled"),
        "deploymentName": expected_proxy_env.get("deploymentName"),
        "serviceName": expected_proxy_env.get("serviceName"),
        "expectedHttpProxy": expected_proxy_env.get("httpProxy"),
        "expectedNoProxy": expected_proxy_env.get("noProxy"),
        "podEnv": proxy_env_runtime,
        "aligned": proxy_env_aligned,
        "valuesPrinted": False,
    },
    "boundary": boundary,
    "serviceDns": "${serviceName}.${target.namespace}.svc.cluster.local:8080",
    "next": {
        "apply": "bun scripts/cli.ts platform-infra sub2api apply --target ${target.id} --confirm",
        "validate": "bun scripts/cli.ts platform-infra sub2api validate --target ${target.id}",
    },
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ok"] else 1)
PY
`;
}

function validateScript(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): string {
  const cleanup = sub2api.defaults.cleanup;
  const dependencyImages = targetDependencyImages(sub2api, target);
  const postgresStatefulSetName = cleanup.externalDbState.postgresStatefulSetName;
  const postgresServiceName = cleanup.externalDbState.postgresServiceName;
  const redisService = sub2api.runtime.redis.serviceName;
  return `
set -u
tmp="$(mktemp -d)"
probe_suffix="$(date +%s)-$$"
pg_probe="unidesk-sub2api-netcheck-pg-$probe_suffix"
redis_probe="unidesk-sub2api-netcheck-redis-$probe_suffix"
cleanup() {
  kubectl -n ${target.namespace} delete pod "$pg_probe" "$redis_probe" --ignore-not-found=true --wait=false >/dev/null 2>&1 || true
  rm -rf "$tmp"
}
trap cleanup EXIT
kubectl get --raw /api/v1/namespaces/${target.namespace}/services/${serviceName}:8080/proxy/health >"$tmp/health.body" 2>"$tmp/health.err"
health_rc=$?
kubectl get --raw /api/v1/namespaces/${target.namespace}/services/${serviceName}:8080/proxy/ >"$tmp/root.body" 2>"$tmp/root.err"
root_rc=$?
kubectl -n ${target.namespace} get networkpolicy allow-all -o json >"$tmp/network-policy.json" 2>"$tmp/network-policy.err"
network_policy_rc=$?
pg_pod="$(kubectl -n ${target.namespace} get pod -l app.kubernetes.io/name=${postgresStatefulSetName} -o jsonpath='{.items[0].metadata.name}' 2>"$tmp/pg-pod.err")"
redis_pod="$(kubectl -n ${target.namespace} get pod -l app.kubernetes.io/name=${redisService} -o jsonpath='{.items[0].metadata.name}' 2>"$tmp/redis-pod.err")"
if [ -n "$pg_pod" ]; then
  kubectl -n ${target.namespace} exec "$pg_pod" -- pg_isready -U sub2api -d sub2api -h 127.0.0.1 >"$tmp/pg.out" 2>"$tmp/pg.err"
  pg_rc=$?
else
  pg_rc=1
  printf '%s\\n' 'sub2api postgres pod not found' >"$tmp/pg.err"
fi
if [ -n "$redis_pod" ]; then
  kubectl -n ${target.namespace} exec "$redis_pod" -- redis-cli ping >"$tmp/redis.out" 2>"$tmp/redis.err"
  redis_rc=$?
else
  redis_rc=1
  printf '%s\\n' 'sub2api redis pod not found' >"$tmp/redis.err"
fi
if ! command -v timeout >/dev/null 2>&1; then
  printf '%s\\n' 'timeout command is required for bounded cross-pod probes' >"$tmp/pg-cross.err"
  printf '%s\\n' 'timeout command is required for bounded cross-pod probes' >"$tmp/redis-cross.err"
  : >"$tmp/pg-cross.out"
  : >"$tmp/redis-cross.out"
  pg_cross_rc=127
  redis_cross_rc=127
else
  timeout 35s kubectl -n ${target.namespace} run "$pg_probe" --restart=Never --rm -i --image=${dependencyImages.postgres} --image-pull-policy=IfNotPresent --command -- pg_isready -h ${postgresServiceName} -U sub2api -d sub2api -t 5 >"$tmp/pg-cross.out" 2>"$tmp/pg-cross.err"
  pg_cross_rc=$?
  timeout 35s kubectl -n ${target.namespace} run "$redis_probe" --restart=Never --rm -i --image=${dependencyImages.redis} --image-pull-policy=IfNotPresent --command -- redis-cli -h ${redisService} -p 6379 ping >"$tmp/redis-cross.out" 2>"$tmp/redis-cross.err"
  redis_cross_rc=$?
fi
python3 - "$tmp" "$health_rc" "$root_rc" "$pg_rc" "$redis_rc" "$network_policy_rc" "$pg_cross_rc" "$redis_cross_rc" <<'PY'
import json
import os
import sys

tmp = sys.argv[1]
health_rc, root_rc, pg_rc, redis_rc, network_policy_rc, pg_cross_rc, redis_cross_rc = [int(value) for value in sys.argv[2:]]

def text(name, limit=4000):
    path = os.path.join(tmp, name)
    try:
        data = open(path, encoding="utf-8", errors="replace").read()
    except FileNotFoundError:
        return ""
    return data[-limit:]

def json_file(name):
    path = os.path.join(tmp, name)
    try:
        return json.load(open(path, encoding="utf-8"))
    except (FileNotFoundError, json.JSONDecodeError):
        return None

def is_allow_all_network_policy(item):
    if not isinstance(item, dict):
        return False
    spec = item.get("spec") or {}
    return (
        item.get("metadata", {}).get("name") == "allow-all"
        and spec.get("podSelector") == {}
        and set(spec.get("policyTypes") or []) == {"Ingress", "Egress"}
        and spec.get("ingress") == [{}]
        and spec.get("egress") == [{}]
    )

health_body = text("health.body", 2000)
root_body = text("root.body", 2000)
network_policy_obj = json_file("network-policy.json")
network_policy_ok = network_policy_rc == 0 and is_allow_all_network_policy(network_policy_obj)
payload = {
    "ok": health_rc == 0 and root_rc == 0 and pg_rc == 0 and redis_rc == 0 and network_policy_ok and pg_cross_rc == 0 and redis_cross_rc == 0,
    "target": "${target.id}",
    "namespace": "${target.namespace}",
    "serviceDns": "${serviceName}.${target.namespace}.svc.cluster.local:8080",
    "checks": {
        "allowAllNetworkPolicy": {
            "exitCode": network_policy_rc,
            "ok": network_policy_ok,
            "method": "kubectl -n ${target.namespace} get networkpolicy allow-all -o json",
            "policyTypes": ((network_policy_obj or {}).get("spec") or {}).get("policyTypes") if isinstance(network_policy_obj, dict) else None,
            "podSelector": ((network_policy_obj or {}).get("spec") or {}).get("podSelector") if isinstance(network_policy_obj, dict) else None,
            "ingress": ((network_policy_obj or {}).get("spec") or {}).get("ingress") if isinstance(network_policy_obj, dict) else None,
            "egress": ((network_policy_obj or {}).get("spec") or {}).get("egress") if isinstance(network_policy_obj, dict) else None,
            "stderr": text("network-policy.err", 2000),
        },
        "sub2apiHealthViaKubernetesServiceProxy": {
            "exitCode": health_rc,
            "method": "kubectl get --raw /api/v1/namespaces/${target.namespace}/services/${serviceName}:8080/proxy/health",
            "bodyPreview": health_body,
            "stderr": text("health.err", 2000),
        },
        "sub2apiRootViaKubernetesServiceProxy": {
            "exitCode": root_rc,
            "method": "kubectl get --raw /api/v1/namespaces/${target.namespace}/services/${serviceName}:8080/proxy/",
            "bodyBytes": len(root_body.encode("utf-8")),
            "bodyPreview": root_body[:400],
            "stderr": text("root.err", 2000),
        },
        "postgresPgIsReady": {
            "exitCode": pg_rc,
            "stdout": text("pg.out", 2000),
            "stderr": text("pg.err", 2000),
        },
        "postgresCrossPodPgIsReady": {
            "exitCode": pg_cross_rc,
            "method": "temporary ${dependencyImages.postgres} pod pg_isready -h ${postgresServiceName} -U sub2api -d sub2api -t 5, bounded by outer timeout",
            "stdout": text("pg-cross.out", 2000),
            "stderr": text("pg-cross.err", 2000),
        },
        "redisPing": {
            "exitCode": redis_rc,
            "stdout": text("redis.out", 2000),
            "stderr": text("redis.err", 2000),
        },
        "redisCrossPodPing": {
            "exitCode": redis_cross_rc,
            "method": "temporary ${dependencyImages.redis} pod redis-cli -h ${redisService} -p 6379 ping, bounded by outer timeout",
            "stdout": text("redis-cross.out", 2000),
            "stderr": text("redis-cross.err", 2000),
        },
    },
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ok"] else 1)
PY
`;
}

function validateExternalActiveScript(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): string {
  const database = sub2api.runtime.database;
  const redisService = sub2api.runtime.redis.serviceName;
  const cleanupPlan = managedResourceCleanupPlan(sub2api, target);
  const exposure = target.publicExposure?.enabled ? target.publicExposure : null;
  const proxy = target.egressProxy?.enabled ? target.egressProxy : null;
  const proxyUrl = proxy === null ? "" : `http://${proxy.serviceName}.${target.namespace}.svc.cluster.local:${proxy.listenPort}`;
  const publicProbeBlock = exposure === null ? `
public_dns_rc=0
public_probe_rc=0
: >"$tmp/public-dns.out"
: >"$tmp/public-dns.err"
: >"$tmp/public-probe.out"
: >"$tmp/public-probe.err"
` : `
public_dns_rc=1
{
  for resolver in ${exposure.dns.resolvers.map((resolver) => shQuote(resolver)).join(" ")}; do
    printf 'resolver=%s\\n' "$resolver"
    dig +short "@$resolver" ${shQuote(exposure.dns.hostname)} A || true
  done
} >"$tmp/public-dns.out" 2>"$tmp/public-dns.err"
if grep -Fx ${shQuote(exposure.dns.expectedA)} "$tmp/public-dns.out" >/dev/null 2>&1; then public_dns_rc=0; fi
curl -fsS --max-time 20 ${shQuote(`${exposure.publicBaseUrl}/health`)} >"$tmp/public-probe.out" 2>"$tmp/public-probe.err"
public_probe_rc=$?
`;
  const egressProbeBlock = proxy === null ? `
egress_deploy_rc=0
egress_svc_rc=0
egress_probe_rc=0
: >"$tmp/egress-deploy.json"
: >"$tmp/egress-deploy.err"
: >"$tmp/egress-svc.json"
: >"$tmp/egress-svc.err"
: >"$tmp/egress-probe.out"
: >"$tmp/egress-probe.err"
` : `
capture_json egress-deploy kubectl -n ${target.namespace} get deployment ${proxy.deploymentName}
egress_deploy_rc=$(cat "$tmp/egress-deploy.rc")
capture_json egress-svc kubectl -n ${target.namespace} get service ${proxy.serviceName}
egress_svc_rc=$(cat "$tmp/egress-svc.rc")
if [ -n "$app_pod" ]; then
  kubectl -n ${target.namespace} exec "$app_pod" -- sh -c 'HTTP_PROXY="$1" HTTPS_PROXY="$1" ALL_PROXY="$1" NO_PROXY="$2" curl -fsS --max-time 20 -o /dev/null -w "status=%{http_code}\\n" "$3"' sh ${shQuote(proxyUrl)} ${shQuote(proxy.noProxy.join(","))} ${shQuote(proxy.healthProbeUrl)} >"$tmp/egress-probe.out" 2>"$tmp/egress-probe.err"
  egress_probe_rc=$?
else
  egress_probe_rc=1
  printf '%s\\n' 'sub2api app pod not found' >"$tmp/egress-probe.err"
fi
`;
  const egressProbeJson = proxy === null ? "None" : `{
        "enabled": True,
        "mode": "master-vpn-subscription-http-proxy",
        "deploymentName": "${proxy.deploymentName}",
        "serviceName": "${proxy.serviceName}",
        "proxyUrl": "${proxyUrl}",
        "healthProbeUrl": "${proxy.healthProbeUrl}",
        "applyToSub2Api": ${proxy.applyToSub2Api ? "True" : "False"},
        "applyToSentinel": ${proxy.applyToSentinel ? "True" : "False"},
        "deployment": {
            "exitCode": egress_deploy_rc,
            "ready": deployment_ready(load("egress-deploy")),
            "stderr": text("egress-deploy.err", 2000),
        },
        "service": {
            "exitCode": egress_svc_rc,
            "type": ((load("egress-svc") or {}).get("spec") or {}).get("type"),
            "clusterIP": ((load("egress-svc") or {}).get("spec") or {}).get("clusterIP"),
            "stderr": text("egress-svc.err", 2000),
        },
        "probe": {
            "exitCode": egress_probe_rc,
            "stdout": text("egress-probe.out", 2000),
            "stderr": text("egress-probe.err", 2000),
        },
        "valuesPrinted": False,
    }`;
  const egressProbeOkExpr = proxy === null ? "True" : "(egress_deploy_rc == 0 and egress_svc_rc == 0 and deployment_ready(load('egress-deploy')) and egress_probe_rc == 0)";
  const publicProbeJson = exposure === null ? "None" : `{
        "enabled": True,
        "publicBaseUrl": "${exposure.publicBaseUrl}",
        "hostname": "${exposure.dns.hostname}",
        "expectedA": "${exposure.dns.expectedA}",
        "mode": "pk01-caddy-frp-direct",
        "dataPath": "client -> PK01 Caddy -> PK01 frps remotePort -> ${target.id} frpc -> Sub2API",
        "dns": {
            "exitCode": public_dns_rc,
            "resolvers": ${JSON.stringify(exposure.dns.resolvers)},
            "stdout": text("public-dns.out", 2000),
            "stderr": text("public-dns.err", 2000),
        },
        "health": {
            "exitCode": public_probe_rc,
            "url": "${exposure.publicBaseUrl}/health",
            "stdout": text("public-probe.out", 2000),
            "stderr": text("public-probe.err", 2000),
        },
    }`;
  const publicProbeOkExpr = exposure === null ? "True" : "(public_dns_rc == 0 and public_probe_rc == 0)";
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
capture_json() {
  name="$1"
  shift
  "$@" -o json >"$tmp/$name.json" 2>"$tmp/$name.err"
  rc=$?
  printf '%s' "$rc" >"$tmp/$name.rc"
}
capture_json networkpolicy kubectl -n ${target.namespace} get networkpolicy allow-all
capture_json secret kubectl -n ${target.namespace} get secret ${database.secretName}
capture_json statefulsets kubectl -n ${target.namespace} get statefulsets
capture_json pvc kubectl -n ${target.namespace} get pvc
app_pod="$(kubectl -n ${target.namespace} get pod -l app.kubernetes.io/name=${serviceName},app.kubernetes.io/component=app -o jsonpath='{.items[0].metadata.name}' 2>"$tmp/app-pod.err" || true)"
redis_pod="$(kubectl -n ${target.namespace} get pod -l app.kubernetes.io/name=${redisService},app.kubernetes.io/component=redis -o jsonpath='{.items[0].metadata.name}' 2>"$tmp/redis-pod.err" || true)"
printf '%s' "$app_pod" >"$tmp/app-pod.txt"
printf '%s' "$redis_pod" >"$tmp/redis-pod.txt"
kubectl get --raw /api/v1/namespaces/${target.namespace}/services/${serviceName}:8080/proxy/health >"$tmp/health.body" 2>"$tmp/health.err"
health_rc=$?
kubectl get --raw /api/v1/namespaces/${target.namespace}/services/${serviceName}:8080/proxy/ >"$tmp/root.body" 2>"$tmp/root.err"
root_rc=$?
if [ -n "$app_pod" ]; then
  kubectl -n ${target.namespace} exec "$app_pod" -- sh -c 'printf "DATABASE_HOST=%s\\n" "$DATABASE_HOST"; printf "DATABASE_PORT=%s\\n" "$DATABASE_PORT"; printf "DATABASE_USER=%s\\n" "$DATABASE_USER"; printf "DATABASE_DBNAME=%s\\n" "$DATABASE_DBNAME"; printf "DATABASE_SSLMODE=%s\\n" "$DATABASE_SSLMODE"; printf "REDIS_HOST=%s\\n" "$REDIS_HOST"; if [ -n "$DATABASE_PASSWORD" ]; then printf "DATABASE_PASSWORD_PRESENT=true\\n"; else printf "DATABASE_PASSWORD_PRESENT=false\\n"; fi' >"$tmp/app-env.out" 2>"$tmp/app-env.err"
  printf '%s' "$?" >"$tmp/app-env.rc"
else
  : >"$tmp/app-env.out"
  printf '%s\\n' 'sub2api app pod not found' >"$tmp/app-env.err"
  printf '%s' "1" >"$tmp/app-env.rc"
fi
if [ -n "$redis_pod" ]; then
  kubectl -n ${target.namespace} exec "$redis_pod" -- redis-cli ping >"$tmp/redis.out" 2>"$tmp/redis.err"
  redis_rc=$?
else
  redis_rc=1
  printf '%s\\n' 'sub2api redis pod not found' >"$tmp/redis.err"
fi
${publicProbeBlock}
${egressProbeBlock}
python3 - "$tmp" "$health_rc" "$root_rc" "$redis_rc" "$public_dns_rc" "$public_probe_rc" "$egress_deploy_rc" "$egress_svc_rc" "$egress_probe_rc" <<'PY'
import json
import os
import sys

tmp = sys.argv[1]
health_rc, root_rc, redis_rc, public_dns_rc, public_probe_rc, egress_deploy_rc, egress_svc_rc, egress_probe_rc = [int(value) for value in sys.argv[2:]]

def rc(name):
    try:
        return int(open(os.path.join(tmp, f"{name}.rc"), encoding="utf-8").read() or "1")
    except FileNotFoundError:
        return 1

def load(name):
    path = os.path.join(tmp, f"{name}.json")
    if not os.path.exists(path):
        return None
    try:
        return json.load(open(path, encoding="utf-8"))
    except json.JSONDecodeError:
        return None

def items(name):
    data = load(name)
    if not isinstance(data, dict):
        return []
    return data.get("items") or []

def text(name, limit=4000):
    path = os.path.join(tmp, name)
    try:
        return open(path, encoding="utf-8", errors="replace").read()[-limit:]
    except FileNotFoundError:
        return ""

def is_allow_all_network_policy(item):
    if not isinstance(item, dict):
        return False
    spec = item.get("spec") or {}
    return (
        item.get("metadata", {}).get("name") == "allow-all"
        and spec.get("podSelector") == {}
        and set(spec.get("policyTypes") or []) == {"Ingress", "Egress"}
        and spec.get("ingress") == [{}]
        and spec.get("egress") == [{}]
    )

def deployment_ready(item):
    if not isinstance(item, dict):
        return False
    spec = item.get("spec") or {}
    status = item.get("status") or {}
    desired = spec.get("replicas", 1)
    return status.get("availableReplicas", 0) >= desired

env = {}
for line in text("app-env.out").splitlines():
    if "=" not in line:
        continue
    key, value = line.split("=", 1)
    env[key] = value

network_policy_obj = load("networkpolicy")
network_policy_ok = rc("networkpolicy") == 0 and is_allow_all_network_policy(network_policy_obj)
secret = load("secret")
secret_keys = sorted(((secret or {}).get("data") or {}).keys())
missing_secret_keys = [key for key in ${JSON.stringify(requiredSecretKeys)} if key not in secret_keys]
cleanup_plan = json.loads(${JSON.stringify(JSON.stringify(cleanupPlan))})
external_db_state = cleanup_plan["externalDbState"]
redis_persistent_state = cleanup_plan["redisPersistentState"]
local_postgres_present = (
    any(item.get("metadata", {}).get("name") == external_db_state["postgresStatefulSetName"] for item in items("statefulsets"))
    or any(item.get("metadata", {}).get("name") in [external_db_state["postgresPvcName"], external_db_state["appDataPvcName"]] for item in items("pvc"))
)
redis_pvc_present = any(item.get("metadata", {}).get("name") == redis_persistent_state["pvcName"] for item in items("pvc"))
env_aligned = (
    rc("app-env") == 0
    and env.get("DATABASE_HOST") == "${database.host}"
    and env.get("DATABASE_PORT") == "${database.port}"
    and env.get("DATABASE_USER") == "${database.user}"
    and env.get("DATABASE_DBNAME") == "${database.dbName}"
    and env.get("DATABASE_SSLMODE") == "${database.sslMode}"
    and env.get("REDIS_HOST") == "${redisService}"
    and env.get("DATABASE_PASSWORD_PRESENT") == "true"
)
payload = {
    "ok": health_rc == 0 and root_rc == 0 and redis_rc == 0 and network_policy_ok and len(missing_secret_keys) == 0 and env_aligned and not local_postgres_present and not redis_pvc_present and ${publicProbeOkExpr} and ${egressProbeOkExpr},
    "target": "${target.id}",
    "namespace": "${target.namespace}",
    "status": "external-db-active",
    "databaseMode": "${target.databaseMode}",
    "externalDatabase": {
        "host": "${database.host}",
        "port": ${database.port},
        "user": "${database.user}",
        "dbName": "${database.dbName}",
        "sslMode": "${database.sslMode}",
        "secretName": "${database.secretName}",
        "passwordKey": "${database.passwordKey}",
        "passwordPrinted": False,
    },
    "publicExposure": ${publicProbeJson},
    "egressProxy": ${egressProbeJson},
    "checks": {
        "allowAllNetworkPolicy": {"exitCode": rc("networkpolicy"), "ok": network_policy_ok, "stderr": text("networkpolicy.err", 2000)},
        "secretReady": {"ok": len(missing_secret_keys) == 0, "missingKeys": missing_secret_keys, "valuesPrinted": False},
        "sub2apiHealthViaKubernetesServiceProxy": {
            "exitCode": health_rc,
            "method": "kubectl get --raw /api/v1/namespaces/${target.namespace}/services/${serviceName}:8080/proxy/health",
            "bodyPreview": text("health.body", 2000),
            "stderr": text("health.err", 2000),
        },
        "sub2apiRootViaKubernetesServiceProxy": {
            "exitCode": root_rc,
            "method": "kubectl get --raw /api/v1/namespaces/${target.namespace}/services/${serviceName}:8080/proxy/",
            "bodyBytes": len(text("root.body").encode("utf-8")),
            "bodyPreview": text("root.body", 400),
            "stderr": text("root.err", 2000),
        },
        "appEnvAligned": {
            "ok": env_aligned,
            "podName": text("app-pod.txt"),
            "env": {key: env.get(key) for key in ["DATABASE_HOST", "DATABASE_PORT", "DATABASE_USER", "DATABASE_DBNAME", "DATABASE_SSLMODE", "REDIS_HOST", "DATABASE_PASSWORD_PRESENT"]},
            "stderr": text("app-env.err", 2000),
        },
        "redisPing": {"exitCode": redis_rc, "podName": text("redis-pod.txt"), "stdout": text("redis.out", 2000), "stderr": text("redis.err", 2000)},
        "externalStateOnly": {"ok": not local_postgres_present and not redis_pvc_present, "localPostgresPresent": local_postgres_present, "redisPvcPresent": redis_pvc_present},
    },
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ok"] else 1)
PY
`;
}

function validateExternalPendingScript(sub2api: Sub2ApiConfig, target: Sub2ApiTargetConfig): string {
  const expectedImage = imageRef(sub2api, target);
  const database = sub2api.runtime.database;
  const redisService = sub2api.runtime.redis.serviceName;
  const cleanupPlan = managedResourceCleanupPlan(sub2api, target);
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
capture_json() {
  name="$1"
  shift
  "$@" -o json >"$tmp/$name.json" 2>"$tmp/$name.err"
  rc=$?
  printf '%s' "$rc" >"$tmp/$name.rc"
}
capture_json ns kubectl get namespace ${target.namespace}
capture_json app kubectl -n ${target.namespace} get deployment ${serviceName}
capture_json redis kubectl -n ${target.namespace} get deployment ${redisService}
capture_json deployments kubectl -n ${target.namespace} get deployments
capture_json services kubectl -n ${target.namespace} get service
capture_json cronjobs kubectl -n ${target.namespace} get cronjob
capture_json statefulsets kubectl -n ${target.namespace} get statefulsets
capture_json pvc kubectl -n ${target.namespace} get pvc
capture_json configmap kubectl -n ${target.namespace} get configmap sub2api-config
capture_json networkpolicy kubectl -n ${target.namespace} get networkpolicy allow-all
python3 - "$tmp" <<'PY'
import json
import os
import sys

tmp = sys.argv[1]

def rc(name):
    try:
        return int(open(os.path.join(tmp, f"{name}.rc"), encoding="utf-8").read() or "1")
    except FileNotFoundError:
        return 1

def load(name):
    path = os.path.join(tmp, f"{name}.json")
    if not os.path.exists(path):
        return None
    try:
        return json.load(open(path, encoding="utf-8"))
    except json.JSONDecodeError:
        return None

def items(name):
    data = load(name)
    if not isinstance(data, dict):
        return []
    return data.get("items") or []

def text(name, limit=2000):
    path = os.path.join(tmp, name)
    try:
        return open(path, encoding="utf-8", errors="replace").read()[-limit:]
    except FileNotFoundError:
        return ""

def is_allow_all_network_policy(item):
    if not isinstance(item, dict):
        return False
    spec = item.get("spec") or {}
    return (
        item.get("metadata", {}).get("name") == "allow-all"
        and spec.get("podSelector") == {}
        and set(spec.get("policyTypes") or []) == {"Ingress", "Egress"}
        and spec.get("ingress") == [{}]
        and spec.get("egress") == [{}]
    )

def deployment_summary(item):
    spec = (item or {}).get("spec") or {}
    status = (item or {}).get("status") or {}
    containers = ((spec.get("template") or {}).get("spec") or {}).get("containers") or []
    volumes = ((spec.get("template") or {}).get("spec") or {}).get("volumes") or []
    desired = spec.get("replicas", 1)
    available = status.get("availableReplicas", 0)
    return {
        "exists": isinstance(item, dict),
        "desired": desired,
        "availableReplicas": available,
        "readyReplicas": status.get("readyReplicas", 0),
        "ready": available >= desired,
        "images": [container.get("image") for container in containers],
        "volumes": volumes,
    }

services = items("services")
deployments = items("deployments")
cronjobs = items("cronjobs")
statefulsets = items("statefulsets")
pvcs = items("pvc")
configmap = load("configmap")
configmap_data = (configmap or {}).get("data") or {}
cleanup_plan = json.loads(${JSON.stringify(JSON.stringify(cleanupPlan))})
external_db_state = cleanup_plan["externalDbState"]
redis_persistent_state = cleanup_plan["redisPersistentState"]
public_exposure_state = cleanup_plan["publicExposure"]
egress_proxy_state = cleanup_plan["egressProxy"]
app = load("app")
redis = load("redis")
app_summary = deployment_summary(app)
redis_summary = deployment_summary(redis)
network_policy_obj = load("networkpolicy")
network_policy_ok = rc("networkpolicy") == 0 and is_allow_all_network_policy(network_policy_obj)
service_names = sorted(item.get("metadata", {}).get("name") for item in services)
local_postgres_present = (
    any(item.get("metadata", {}).get("name") == external_db_state["postgresServiceName"] for item in services)
    or any(item.get("metadata", {}).get("name") == external_db_state["postgresStatefulSetName"] for item in statefulsets)
    or any(item.get("metadata", {}).get("name") in [external_db_state["postgresPvcName"], external_db_state["appDataPvcName"]] for item in pvcs)
)
redis_pvc_present = any(item.get("metadata", {}).get("name") == redis_persistent_state["pvcName"] for item in pvcs)
public_exposure_deployment_present = any(item.get("metadata", {}).get("name") == public_exposure_state["deploymentName"] for item in deployments)
egress_proxy_deployment_present = any(item.get("metadata", {}).get("name") == egress_proxy_state["deploymentName"] for item in deployments)
egress_proxy_service_present = egress_proxy_state["serviceName"] in service_names
sentinel_cronjob_present = any(item.get("metadata", {}).get("name") == "${codexPoolSentinelResourceNames().cronJobName}" for item in cronjobs)
standby_disabled_ok = (
    not public_exposure_deployment_present
    and not egress_proxy_deployment_present
    and not egress_proxy_service_present
    and not sentinel_cronjob_present
)
redis_ephemeral = any(volume.get("emptyDir") == {} for volume in redis_summary["volumes"])
configmap_aligned = (
    configmap_data.get("DATABASE_HOST") == "${database.host}"
    and configmap_data.get("DATABASE_PORT") == "${database.port}"
    and configmap_data.get("DATABASE_USER") == "${database.user}"
    and configmap_data.get("DATABASE_DBNAME") == "${database.dbName}"
    and configmap_data.get("DATABASE_SSLMODE") == "${database.sslMode}"
    and configmap_data.get("REDIS_HOST") == "${redisService}"
)
app_scaled_to_zero = app_summary["exists"] and app_summary["desired"] == ${target.appReplicas} and ${target.appReplicas} == 0
image_aligned = "${expectedImage}" in app_summary["images"]
redis_ready = redis_summary["exists"] and redis_summary["desired"] == ${target.redisReplicas} and redis_ephemeral and (redis_summary["ready"] or ${target.redisReplicas} == 0)
payload = {
    "ok": rc("ns") == 0 and network_policy_ok and app_scaled_to_zero and image_aligned and redis_ready and configmap_aligned and not local_postgres_present and not redis_pvc_present and standby_disabled_ok and "${serviceName}" in service_names and "${redisService}" in service_names,
    "target": "${target.id}",
    "namespace": "${target.namespace}",
    "status": "pending-external-db",
    "databaseMode": "${target.databaseMode}",
    "redisMode": "${target.redisMode}",
    "expectedRedisReplicas": ${target.redisReplicas},
    "externalDatabase": {
        "sourceRef": "${database.sourceRef}",
        "host": "${database.host}",
        "port": ${database.port},
        "user": "${database.user}",
        "dbName": "${database.dbName}",
        "sslMode": "${database.sslMode}",
        "secretName": "${database.secretName}",
        "passwordKey": "${database.passwordKey}",
        "pendingAllowed": ${database.pendingAllowed ? "True" : "False"},
        "passwordPrinted": False,
    },
    "checks": {
        "namespaceExists": rc("ns") == 0,
        "allowAllNetworkPolicy": {"ok": network_policy_ok, "stderr": text("networkpolicy.err")},
        "appScaledToZero": {"ok": app_scaled_to_zero, "summary": app_summary},
        "imageAligned": {"ok": image_aligned, "desiredImage": "${expectedImage}", "runningImages": app_summary["images"]},
        "redisReadyEphemeral": {"ok": redis_ready, "summary": redis_summary, "redisPvcPresent": redis_pvc_present, "readinessRequired": ${target.redisReplicas} > 0},
        "serviceBoundary": {"serviceNames": service_names, "servicePresent": "${serviceName}" in service_names, "redisServicePresent": "${redisService}" in service_names},
        "externalDbOnly": {"ok": not local_postgres_present, "localPostgresPresent": local_postgres_present},
        "standbyDisabled": {
            "ok": standby_disabled_ok,
            "publicExposureDeploymentPresent": public_exposure_deployment_present,
            "egressProxyDeploymentPresent": egress_proxy_deployment_present,
            "egressProxyServicePresent": egress_proxy_service_present,
            "sentinelCronJobPresent": sentinel_cronjob_present,
        },
        "configMapAligned": {"ok": configmap_aligned, "databaseHost": configmap_data.get("DATABASE_HOST"), "redisHost": configmap_data.get("REDIS_HOST")},
    },
    "next": {
        "status": "bun scripts/cli.ts platform-infra sub2api status --target ${target.id}",
        "activateAfterDbReady": "update config/platform-infra/sub2api.yaml target ${target.id} appReplicas and redisReplicas to 1 after ${database.sourceRef}, ${database.secretName}/${database.passwordKey}, and runtime images are ready, then apply --target ${target.id} --confirm",
    },
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ok"] else 1)
PY
`;
}

function boolField(value: Record<string, unknown> | null, key: string, defaultValue: boolean): boolean {
  if (value === null) return defaultValue;
  const field = value[key];
  return typeof field === "boolean" ? field : defaultValue;
}

function asRecordOrNull(value: unknown): Record<string, unknown> | null {
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value as Record<string, unknown> : null;
}
