#!/usr/bin/env python3
"""Fail if any agent-work systemd slice in the repo carries a kill-prone
resource setting. Owner doctrine 2026-08-15 (born from same-day incidents):

  - CPUQuota on an agent slice is FORBIDDEN. A hard quota (CPUQuota=150%)
    starved every agent tool shell under contention. CPUWeight is
    proportional and cannot starve; it is the only permitted CPU control.
  - MemoryHigh/MemoryMax on agent.slice are FORBIDDEN. MemoryHigh froze the
    box once (8.7M reclaim events). Memory pressure is handled by
    ManagedOOMMemoryPressure (stall-based), never a hard level.
  - pids.max (systemd: TasksMax) is REQUIRED on agent.slice. New forks fail
    once the cap is hit; existing work keeps running. True forkbombs are
    handled separately by pids-guard's victim-share floor (>=10%,
    commit 0fe056c2d), not by this slice.

Run standalone: python3 fleet/roles/systemd_units/files/policy_lint.py
Exit 0 = clean, 1 = a forbidden setting was found (blocks landing).
"""
from __future__ import annotations

import pathlib
import re
import sys

REPO_ROOT = pathlib.Path(__file__).resolve().parents[4]
AGENT_SLICE_GLOBS = [
    "modules/monitor/systemd/user/agent.slice",
    "modules/monitor/systemd/user/agent.slice.d/*.conf",
]

FORBIDDEN_CPU_QUOTA = re.compile(r"^\s*CPUQuota\s*=\s*[0-9]", re.MULTILINE)
FORBIDDEN_MEM_HIGH = re.compile(r"^\s*MemoryHigh\s*=", re.MULTILINE)
FORBIDDEN_MEM_MAX = re.compile(r"^\s*MemoryMax\s*=", re.MULTILINE)
TASKS_MAX = re.compile(r"^\s*TasksMax\s*=\s*\S+", re.MULTILINE)


def find_agent_slice_files() -> list[pathlib.Path]:
    found: list[pathlib.Path] = []
    for pattern in AGENT_SLICE_GLOBS:
        found.extend(sorted(REPO_ROOT.glob(pattern)))
    return found


def lint() -> list[str]:
    files = find_agent_slice_files()
    if not files:
        return ["no agent.slice source file found under modules/monitor/systemd/user/"]

    errors: list[str] = []
    combined = "\n".join(f.read_text() for f in files)

    for f in files:
        text = f.read_text()
        if FORBIDDEN_CPU_QUOTA.search(text):
            errors.append(f"{f}: CPUQuota= with a numeric value is forbidden on agent slices "
                          "(hard quota starves shells under contention; use CPUWeight only)")
        if FORBIDDEN_MEM_HIGH.search(text):
            errors.append(f"{f}: MemoryHigh= is forbidden on agent.slice (froze the box once; "
                          "use ManagedOOMMemoryPressure, stall-based)")
        if FORBIDDEN_MEM_MAX.search(text):
            errors.append(f"{f}: MemoryMax= is forbidden on agent.slice (hard level, same failure "
                          "family as MemoryHigh)")

    if not TASKS_MAX.search(combined):
        errors.append("no TasksMax= (pids.max) found across agent.slice + its drop-ins — "
                      "required so a forkbomb fails new forks instead of needing a kill")

    return errors


def main() -> int:
    errors = lint()
    if errors:
        for e in errors:
            print(f"POLICY LINT FAIL: {e}", file=sys.stderr)
        return 1
    print(f"policy lint clean: {len(find_agent_slice_files())} agent-slice source file(s) checked")
    return 0


if __name__ == "__main__":
    sys.exit(main())
