#!/usr/bin/env bash
# CI containment is fleet policy: check the declared slice, both box-side consumers,
# and the in-repo workflow guard with a synthetic failing workflow.
set -euo pipefail

REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
SLICE="$REPO/modules/buildbox/user-config/systemd/ci.slice"
APPLY="$REPO/modules/buildbox/host-config/apply.sh"
RUNNER_SLICES="$REPO/modules/buildbox/user-config/bin/buildbox-converge-runner-slices.sh"
IMAGE_BUILD="$REPO/modules/sandbox/host/bin/sandbox-image-build"
CHECK="$REPO/modules/buildbox/bin/check-ci-sched-idle"
WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT

fail() { printf 'FAIL %s\n' "$1" >&2; exit 1; }

for setting in 'CPUQuota=500%' 'MemoryHigh=20G' 'MemoryMax=24G' 'IOWeight=50' 'CPUWeight=80'; do
  grep -qxF "$setting" "$SLICE" || fail "ci.slice missing $setting"
done
node --input-type=module <<'NODE' || fail 'fleet expansion does not declare ci slice and runner convergence'
import assert from 'node:assert/strict';
import { loadFleet } from './lib/fleet/loader.mjs';
import { expandNode } from './lib/fleet/expand.mjs';
import { loadRegistry } from './modules/workstation/claude/lib/buildbox-registry.mjs';

const fleet = loadFleet(undefined, {
  loadRegistry: () => loadRegistry({ BUILDBOX_HOSTS_CONFIG: './modules/workstation/claude/buildbox-hosts.json' }),
});
const items = expandNode(fleet, 'debian1');
assert.deepEqual(
  items.find((item) => item.id === 'buildbox:user-config:systemd/ci.slice')?.strategy,
  'unit',
);
assert.equal(
  items.find((item) => item.id === 'buildbox:user-config:runner-slice')?.strategy,
  'runner-slice',
);
NODE
grep -Fq 'converge_runner_slices' "$APPLY" && fail 'dead runner convergence remains in apply.sh'
grep -Fq 'systemd-user-root' "$APPLY" && fail 'dead systemd-user-root install remains in apply.sh'
grep -Fq 'systemd-run --user --scope --quiet --collect --slice=ci.slice' "$IMAGE_BUILD" \
  || fail 'sandbox image build is outside ci.slice'

mkdir -p "$WORK/home/actions-runner-overdeck" "$WORK/bin"
cat >"$WORK/bin/systemctl" <<'SH'
#!/usr/bin/env bash
set -euo pipefail
case "$2" in
  list-unit-files) printf 'runner-overdeck.service enabled\n' ;;
  show) printf 'ExecStart=%s/run.sh\n' "$FAKE_RUNNER" ;;
  daemon-reload) printf 'reload\n' >>"$SYSTEMCTL_LOG" ;;
  restart) printf 'restart %s\n' "$3" >>"$SYSTEMCTL_LOG" ;;
  *) printf 'unexpected systemctl invocation: %s\n' "$*" >&2; exit 2 ;;
esac
SH
chmod +x "$WORK/bin/systemctl"
if HOME="$WORK/home" PATH="$WORK/bin:$PATH" FAKE_RUNNER="$WORK/home/actions-runner-overdeck" \
  SYSTEMCTL_LOG="$WORK/systemctl.log" "$RUNNER_SLICES" --audit; then
  fail 'runner drop-in audit passed before materialization'
fi
HOME="$WORK/home" PATH="$WORK/bin:$PATH" FAKE_RUNNER="$WORK/home/actions-runner-overdeck" \
  SYSTEMCTL_LOG="$WORK/systemctl.log" "$RUNNER_SLICES" || fail 'runner drop-in did not materialize'
DROPIN="$WORK/home/.config/systemd/user/runner-overdeck.service.d/ci-slice.conf"
cmp <(printf '[Service]\nSlice=ci.slice\n') "$DROPIN" || fail 'runner drop-in content is wrong'
grep -qxF 'reload' "$WORK/systemctl.log" || fail 'runner drop-in did not reload user manager'
grep -qxF 'restart runner-overdeck.service' "$WORK/systemctl.log" || fail 'runner drop-in did not restart runner'
HOME="$WORK/home" PATH="$WORK/bin:$PATH" FAKE_RUNNER="$WORK/home/actions-runner-overdeck" \
  SYSTEMCTL_LOG="$WORK/systemctl.log" "$RUNNER_SLICES" --audit || fail 'runner drop-in audit remained drifted'

mkdir -p "$WORK/runners/actions-runner-overdeck" "$WORK/overdeck/.github/workflows"
cat >"$WORK/overdeck/.github/workflows/gate.yml" <<'YAML'
jobs:
  gate:
    runs-on: [self-hosted, linux]
    steps:
      - run: ./scripts/cpu-limit.sh pnpm test
YAML
if CI_RUNNER_HOME="$WORK/runners" OVERDECK_REPO_ROOT="$WORK/overdeck" "$CHECK" >"$WORK/out" 2>&1; then
  fail 'missing BUILD_SCHED_IDLE=0 passed'
fi
grep -Fq "$WORK/overdeck/.github/workflows/gate.yml:5" "$WORK/out" \
  || fail 'missing setting did not name workflow line'

sed -i '3i\    env:\n      BUILD_SCHED_IDLE: "0"' "$WORK/overdeck/.github/workflows/gate.yml"
CI_RUNNER_HOME="$WORK/runners" OVERDECK_REPO_ROOT="$WORK/overdeck" "$CHECK" \
  >"$WORK/out" 2>&1 || fail 'BUILD_SCHED_IDLE=0 did not pass'

mkdir -p "$WORK/runners/actions-runner-external" "$WORK/repos/external/.github/workflows"
cp "$WORK/overdeck/.github/workflows/gate.yml" "$WORK/repos/external/.github/workflows/gate.yml"
sed -i '/BUILD_SCHED_IDLE/d' "$WORK/repos/external/.github/workflows/gate.yml"
CI_RUNNER_HOME="$WORK/runners" CI_REPOS_ROOT="$WORK/repos" OVERDECK_REPO_ROOT="$WORK/overdeck" "$CHECK" \
  >"$WORK/out" 2>&1 || fail 'external workflow finding failed the check'
grep -Fq 'ADVISORY' "$WORK/out" || fail 'external workflow finding was not advisory'

printf 'ok   ci containment declares quotas, reports runner gaps, and gates SCHED_IDLE\n'
