#!/usr/bin/python3
"""hilt — a query surface for macOS configuration, state and apps.

Sheath's shape on the Mac: a DERIVED index of what this machine can be asked
to do, behind find / describe / owners / orient / coverage / traps, with
three-valued answers so an agent can tell "checked and unwritten" from
"nothing was checked".

Spec: docs/spec.md. Cuts shipped here: A (scan + index, orient, coverage),
B (find, describe, owners) and C (run). `run` probes before and after and
refuses before acting on anything the index did not type. CUT D's MCP door
(tools/hilt-mcp) relays `hilt <verb> --json`; every JSON answer therefore
carries a `verdict`, so the door never has to translate an exit code.

`--` ends options: `hilt find -- --json` searches for the text "--json", and
`hilt run <id> -- --no-reload` passes "--no-reload" as an argument (which the
typed params then refuse). The door always sends `--`.

Exit codes are API:
  0  an answer (including UNOWNED / CONTESTED); run: verified or query
  1  run: failed — the actuator itself exited non-zero
  2  refused, unknown id, unknown verb, or a question hilt does not answer
  3  VACUOUS — the target does not exist, so nothing was checked
  4  UNVERIFIABLE — the target exists but the evidence source is down;
     run: the actuator exited 0 and no probe can observe its effect
  5  run: mismatched — the actuator exited 0 and the probe did NOT move to
     the requested state. A no-op, never a success.
"""
import difflib
import functools
import shlex
import sqlite3
import glob
import json
import os
import plistlib
import re
import signal
import subprocess
import sys
import time
import xml.etree.ElementTree as ET

HILT_VERSION = "0.10.3"  # bumps with each shipped change; the CONTRACT bumps only when the JSON/verb surface breaks
HILT_CONTRACT = "4"  # 4: permissions verb, find --criteria, anchor/state records. 3: path params, verdict everywhere, `--`

STATE = os.environ.get("XDG_STATE_HOME") or os.path.expanduser("~/.local/state")
INDEX = os.environ.get("HILT_INDEX") or os.path.join(STATE, "hilt", "index.json")
RUNS = os.environ.get("HILT_RUNS") or os.path.join(STATE, "hilt", "runs.jsonl")

EXT_DIR = "/System/Library/ExtensionKit/Extensions"
# Names people still SAY for an app whose bundle name changed (System Preferences
# became System Settings in macOS 13) or that they shorten. Voice test, Zil #hilt 144:
# "open system preferences" reached a Privacy pane instead of the app.
APP_OTHER_NAMES = {"com.apple.systempreferences": ("system preferences", "preferences", "settings",
                                                   "settings app", "system prefs")}
APP_ROOTS = ["/Applications", "/System/Applications", "/System/Applications/Utilities",
             "/System/Library/CoreServices", os.path.expanduser("~/Applications")]
PREFS_USER = os.path.expanduser("~/Library/Preferences")
PREFS_SYSTEM = "/Library/Preferences"
GLOBAL_DOMAINS = {"NSGlobalDomain", ".GlobalPreferences", "Apple Global Domain"}

# Apple config CLIs the corpus expects, and the gaps people fill with
# third-party tools. Absence is a HOLE reported by orient, never a zero.
EXPECTED_CLIS = ["defaults", "networksetup", "pmset", "scutil", "systemsetup", "tmutil",
                 "softwareupdate", "shortcuts", "osascript", "open", "lsappinfo", "profiles",
                 "launchctl", "hidutil", "sdef", "mdfind", "mdutil"]
# Named by the third-party tool people reach for; hilt does NOT recommend them
# (Mark 2026-09-24: native first). Each gap is native work in docs/backlog.md.
HOLE_CLIS = {
    "blueutil": "Bluetooth power/pairing — Apple ships no CLI; native path in docs/backlog.md",
    "displayplacer": "display arrangement/resolution — Apple ships no CLI; native path in docs/backlog.md",
    "SwitchAudioSource": "audio output/input device — Apple ships no CLI; native path in docs/backlog.md",
    "brightness": "display brightness — Apple ships no CLI; native path in docs/backlog.md",
    "airport": "Wi-Fi scan/association — Apple removed it",
}

KIND_RANK = {"system.setting": 0, "system.pane": 1, "application.launch": 2, "system.state": 3,
             "system.cli": 4, "application.verb": 5, "shortcut.run": 6, "system.intent": 7}

# The probe ladder (spec §4). ONE function; build, find and describe all read
# its answer. Sheath's `find` kept its own copy and printed probe:NONE for
# probed routes — that is the defect this placement designs out.
PROBE_LADDER = ("readback", "paired-query", "owned-file", "generic-delta", "authored",
                "declared-unobservable", "none")


# ---------------------------------------------------------------- label + latency (Zil ASK mode, #hilt 125)
# A numbered PICK row is READ ALOUD, so every record carries a short speakable
# `label` ("Dock: hide", "Privacy: All Files", "Open Slack") and how long `run`
# takes, so Zil knows when to show a "working…" row. Latency is MEASURED (median
# of this Mac's runs.jsonl) when the record has run, else DECLARED for known-slow
# reads, else a default by kind — `latency_source` says which.
LABELS = {  # hand labels for records hilt authored (derived ones cover the rest)
    "state.battery": "Battery", "state.uptime": "Uptime", "state.disk": "Disk space",
    "state.wifi.current": "Wi-Fi signal", "state.audio.now": "Volume and output",
    "state.bluetooth.connected": "Connected Bluetooth", "state.focus": "Focus",
    "state.display.brightness": "Screen brightness", "native.focus.set": "Set Do Not Disturb",
    "native.audio.volume": "Set volume", "native.audio.mute": "Mute sound", "native.wifi.power": "Wi-Fi on or off",
    "native.appearance.dark": "Dark mode", "native.screen.lock": "Lock the screen",
    "native.bluetooth.power": "Bluetooth on or off", "native.nightshift": "Night Shift",
    "native.lowpower": "Low Power Mode", "native.display.brightness": "Screen brightness", "state.nightshift": "Is Night Shift on",
    "state.resources": "Memory and CPU", "state.thermal.sensors": "Temperatures", "state.fleet.macs": "My Macs",
    "state.audio.devices": "Audio devices", "native.audio.output": "Audio output", "native.audio.input": "Audio input",
    "state.bluetooth.devices": "Bluetooth devices", "native.bluetooth.connect": "Connect Bluetooth",
    "native.bluetooth.disconnect": "Disconnect Bluetooth", "state.bluetooth.nearby": "Nearby Bluetooth",
    "state.bluetooth.mine-nearby": "Are my AirPods near", "state.dev.xcode": "Xcode and Swift",
    "state.quarantine.agents": "Quarantined tools", "state.permissions": "App permissions",
    "system.findmy.devices": "Find My devices", "state.firewall": "Firewall", "state.firewall.stealth": "Stealth mode",
    "state.sharing.remote-login": "Sharing: SSH", "state.sharing.screen-sharing": "Sharing: Screen",
    "state.sharing.file-sharing": "Sharing: Files", "state.sharing.remote-management": "Sharing: Remote Management",
    "state.sharing.printer-sharing": "Sharing: Printers", "state.sharing.content-caching": "Sharing: Content Caching",
    "cli.networkquality": "Speed test", "cli.sp.wifi": "Wi-Fi details", "cli.sp.usb": "USB devices",
    "cli.route.default": "Default gateway", "cli.scutil.dns": "DNS servers", "cli.ipconfig.getifaddr": "My IP address",
}
DECLARED_MS = {"cli.networkquality": 20000, "cli.sp.wifi": 5000, "state.bluetooth.nearby": 12000,
               "state.resources": 3700, "state.dev.xcode": 600}
AREA = {"missioncontrol": "Mission Control", "windows": "Windows", "screenshot": "Screenshots",
        "privacysecurity": "Privacy", "controlcenter": "Control Center", "desktop": "Desktop & Dock"}


def _pretty(seg):
    seg = re.sub(r"^(Privacy|Services|Security)_", "", seg)
    return AREA.get(seg.lower()) or re.sub(r"[-_.]+", " ", words(seg)).strip().title()


def record_label(r, by_id):
    """Short (<= 32 chars), speakable, no dots or arrows."""
    rid, k = r["id"], r["kind"]
    if rid in LABELS:
        lab = LABELS[rid]
    elif r.get("x_label_authored"):
        lab = r["x_label_authored"]
    elif k == "system.intent":
        o = re.sub(r"^(Update|Set|Get|Open)\s+(an?\s+|the\s+)?", lambda m: "" if m.group(1) == "Update" else m.group(1) + " ",
                   r["outcome"])
        m = re.match(r"^(.*?)'s\s+(.*)$", o)  # "dock settings's Size" -> "Dock settings: Size"
        lab = (m.group(1).strip().capitalize() + ": " + m.group(2).strip()) if m else o[:1].upper() + o[1:]
    elif k == "system.setting":
        area = _pretty(rid.split(".")[1])
        alias = next((a for a in r.get("x_aliases", []) if len(a.split()) <= 4), None)
        act = alias or rid.split(".")[-1].replace("-", " ")
        for w in area.lower().split():
            act = re.sub(rf"\b{re.escape(w)}\b\s*", "", act, flags=re.I).strip()
        lab = f"{area}: {act or rid.split('.')[-1].replace('-', ' ')}"
    elif k == "system.pane":
        parent = by_id.get(r.get("x_parent")) if r.get("x_anchor") else r
        page = re.sub(r"^open\s+|\s+settings.*$", "", (parent or r)["outcome"], flags=re.I).strip()
        lab = f"{page}: {_pretty(r['x_anchor'])}" if r.get("x_anchor") else f"Settings: {page}"
        if menu_bar_option(r):  # label = outcome: it is the ICON's setting, not the thing (Zil handoff #3)
            m = re.match(r"show (.+?)(?: status)? in (?:the )?menu bar", (r.get("x_titles") or [""])[0])
            lab = f"Menu bar: {(m.group(1) if m else _pretty(r['x_anchor'])).title()} icon"
    elif k == "application.launch":
        lab = "Open " + r["outcome"][len("open "):] + (" (Chrome)" if r.get("x_bundle", "").startswith("com.google.Chrome.app.")
                                                       else " (web app)" if ".WebApp." in r.get("x_bundle", "") else "")
    elif k == "application.verb":
        m = re.match(r"^(.*) \((.*)\)$", r["outcome"])
        lab = f"{m.group(2)}: {m.group(1)}" if m else r["outcome"]
    elif k == "shortcut.run":
        lab = "Shortcut: " + r["outcome"].split(": ", 1)[-1]
    else:
        lab = (r.get("x_aliases") or [r["outcome"]])[0]
        lab = lab[:1].upper() + lab[1:]
    lab = re.sub(r"[.›→]+", " ", lab).replace("  ", " ").strip()
    return lab if len(lab) <= 32 else lab[:31].rstrip() + "…"


# Zil ASK v2 (#hilt 133): an agent can now trigger runs, so Zil's confirm-once row
# comes from hilt's data. `irreversible` is conservative: anything whose effect hilt
# cannot see (a user Shortcut) counts as irreversible. `undo` says how to reverse.
IRREVERSIBLE_VERB = re.compile(r"(delete|erase|remove|empty|trash|send|reply|forward|quit|shut\s*down|restart|"
                               r"log\s*out|eject|format|purge|destroy|reset|uninstall)", re.I)


def record_safety(r):
    k, rid = r["kind"], r["id"]
    if k in ("system.state", "system.pane", "system.intent"):
        return False, "nothing to undo (read-only, or a human finishes in Settings)"
    if k == "system.setting":
        return False, "run it again with the value in `before`"
    if k == "application.launch":
        return False, "quit the app (a human, or CUT F's quit verb once shipped)"
    if rid.startswith("native.audio."):
        return False, "switch back to the device in `before`"
    if rid == "native.bluetooth.connect":
        return False, "native.bluetooth.disconnect <same device>"
    if rid == "native.bluetooth.disconnect":
        return False, "native.bluetooth.connect <same device>"
    if k == "shortcut.run":
        return True, "unknown: a user Shortcut's effect is opaque to hilt, so treat it as irreversible"
    if k == "application.verb":
        verb = r["outcome"].split(" (")[0]
        return (True, f"'{verb}' cannot be undone by hilt") if IRREVERSIBLE_VERB.search(verb) else \
            (False, "a scripting verb; its inverse depends on the app")
    if k == "system.cli" and r.get("x_cli_authored"):
        return bool(r.get("x_irreversible_authored")), r.get("x_undo_text") or "set it back by hand"
    if k == "system.cli":
        if IRREVERSIBLE_VERB.search(rid.rsplit(".", 1)[-1]):
            return True, "a remove/delete: recreate it by hand"
        return False, "the paired getter's `before` shows the prior value" if r.get("x_probe_argv") else "set it back by hand"
    return True, "unclassified: treat as irreversible"


def run_medians():
    import statistics
    d = {}
    try:
        for line in open(RUNS):
            try:
                x = json.loads(line)
            except ValueError:
                continue
            if x.get("verdict") in ("verified", "query", "mismatched") and x.get("seconds") is not None and x.get("id"):
                d.setdefault(x["id"], []).append(x["seconds"])
    except OSError:
        pass
    return {k: (statistics.median(v), len(v)) for k, v in d.items()}


def record_latency(r, med):
    if r["id"] in med:
        ms, src = round(med[r["id"]][0] * 1000), f"measured (median of {med[r['id']][1]} run(s) here)"
    elif r["id"] in DECLARED_MS:
        ms, src = DECLARED_MS[r["id"]], "declared"
    else:
        k = r["kind"]
        ms = (1500 if k == "system.setting" and r.get("x_reload") else 2000 if k == "application.launch"
              else 3000 if k == "shortcut.run"  # a user Shortcut can do anything: assume slow until measured
              else 300 if k in ("system.pane", "system.setting", "system.state", "system.cli") else None)
        src = "default by kind"
    cls = None if ms is None else ("instant" if ms < 300 else "short" if ms < 1500 else "slow")
    return {"latency": cls, "latency_ms": ms, "latency_source": src}


def probe_kind(rec):
    k = rec.get("kind")
    if k == "system.setting" and rec.get("probe"):
        return "readback"
    if k == "system.cli" and rec.get("x_cli_probe"):
        return "authored"  # CUT H: the row's own regex / file / paired probe
    if k in ("application.launch", "system.cli") and rec.get("probe"):
        return "paired-query"
    if k == "system.state":
        return "query"
    if rec.get("x_probe_authored"):
        return "authored"
    if k == "system.pane":
        return "declared-unobservable"
    return "none"


# ---------------------------------------------------------------- helpers

def sh(argv, timeout=60):
    try:
        r = subprocess.run(argv, capture_output=True, text=True, timeout=timeout,
                           stdin=subprocess.DEVNULL)
        return r.returncode, r.stdout, r.stderr
    except FileNotFoundError:
        return 127, "", "not found"
    except subprocess.TimeoutExpired:
        return 124, "", "timeout"


def which(c):
    for d in os.environ.get("PATH", "").split(":") + ["/usr/bin", "/usr/sbin", "/bin", "/sbin"]:
        p = os.path.join(d, c)
        if os.path.isfile(p) and os.access(p, os.X_OK):
            return p
    return None


def read_plist(path):
    try:
        with open(path, "rb") as f:
            return plistlib.load(f)
    except Exception:
        return None


def norm(s):
    return re.sub(r"[^a-z0-9]+", "", (s or "").lower())


def words(s):
    s = re.sub(r"([a-z])([A-Z])", r"\1 \2", s or "")
    return re.sub(r"[^A-Za-z0-9&]+", " ", s).strip()


def ptype(v):
    return {bool: "boolean", int: "integer", float: "float", str: "string", bytes: "data",
            list: "array", dict: "dictionary"}.get(type(v), type(v).__name__)


# ---------------------------------------------------------------- scanners
# Each scanner returns (records, source_row). A source row always carries a
# count AND a denominator, or a status saying why it has none.

def scan_bundle_ids():
    """One Spotlight query maps every indexed bundle id to its path(s)."""
    rc, out, _ = sh(["mdutil", "-s", "/"], 20)
    spotlight = "enabled" if "Indexing enabled" in out else ("disabled" if rc == 0 else "unknown")
    bids = {}
    if spotlight == "enabled":
        rc, out, _ = sh(["mdfind", "-0", "-attr", "kMDItemCFBundleIdentifier",
                         "kMDItemCFBundleIdentifier == '*'"], 60)
        for row in out.split("\0"):
            m = re.match(r"^(.*?)\s+kMDItemCFBundleIdentifier = (.+)$", row.strip())
            if m and m.group(2) != "(null)":
                bids.setdefault(m.group(2), []).append(m.group(1))
    return spotlight, bids


def scan_panes():
    recs, seen = [], 0
    anchors = {"records": 0, "keys": 0, "files": 0, "unreadable": 0}
    for a in sorted(glob.glob(os.path.join(EXT_DIR, "*.appex"))):
        info = read_plist(os.path.join(a, "Contents", "Info.plist")) or {}
        ep = (info.get("EXAppExtensionAttributes") or {}).get("EXExtensionPointIdentifier")
        if ep != "com.apple.Settings.extension.ui":
            continue
        seen += 1
        bid = info.get("CFBundleIdentifier", "")
        stem = os.path.basename(a)[:-len(".appex")]
        disp = info.get("CFBundleDisplayName") or info.get("CFBundleName") or stem
        bid_word = re.sub(r"^com\.apple\.(settings\.|systempreferences\.)?", "", bid)
        bid_word = re.split(r"[-.]?settings|\.", bid_word, maxsplit=1, flags=re.I)[0]
        clean = lambda s: re.sub(r"\b(Settings?|Extension|Ext|Preferences?|Pane|macOS)\b", "",
                                 words(s)).strip()
        names = [n for n in dict.fromkeys([clean(disp), clean(stem), words(bid_word).replace("-", " ")]) if n]
        title = names[0] if names else stem
        slug = norm(bid_word) or norm(title)
        legacy = ((info.get("SettingsExtensionAttributes") or {}).get("legacyBundleIdentifier"))
        recs.append({
            "id": f"system.pane.{slug}",
            "kind": "system.pane",
            "outcome": f"open {title} settings",
            "provider": f"open:x-apple.systempreferences:{bid}",
            "authority": "human-required",
            "probe": None,
            "x_aliases": sorted({n.lower() for n in names} | {title.lower() + " settings"}),
            "x_bundle": bid,
            "x_legacy_bundle": legacy,
            "x_path": a,
            "x_note": "Opens the pane; a human finishes the change. The deep-link form is "
                      "derived from the bundle id and is NOT yet exercised (CUT C).",
            "x_source": ["settings-pane"],
        })
        recs += pane_anchors(a, bid, slug, title, anchors)
    return recs, {"count": len(recs) - anchors["records"], "denominator": seen,
                  "unit": "Settings.extension.ui appexes indexed as panes"}, anchors


SEARCH_LPROJ = "en.lproj"


def pane_anchors(appex, bid, slug, title, tally):
    """Sub-page records from the pane's own Settings search index
    (`<lproj>/*.searchTerms`: anchor -> localized titles + search words). This
    is Apple's map of what System Settings search can land on, so "full disk
    access" finds Privacy_AllFiles without anyone typing the anchor list."""
    out = []
    for f in sorted(glob.glob(os.path.join(appex, "Contents", "Resources", SEARCH_LPROJ, "*.searchTerms"))):
        d = read_plist(f)
        tally["files"] += 1
        if not isinstance(d, dict):
            tally["unreadable"] += 1
            continue
        for anchor, v in d.items():
            tally["keys"] += 1
            strs = [x for x in ((v or {}).get("localizableStrings") or []) if isinstance(x, dict)]
            titles = [x["title"] for x in strs if x.get("title")]
            terms = [t.strip().lower() for x in strs for t in (x.get("index") or "").split(",") if t.strip()]
            short = re.sub(r"^(Privacy|Services|Security)_", "", anchor)
            aid = f"system.pane.{slug}.{norm(short) or norm(anchor)}"
            taken = {r["id"] for r in out}
            if aid in taken:
                aid = f"system.pane.{slug}.{norm(anchor)}"
            n = 2
            while aid in taken:  # AX_FEATURE_ZOOM and AX_feature.zoom both ship
                aid, n = f"system.pane.{slug}.{norm(anchor)}-{n}", n + 1
            et = titles[0] if titles else words(short)
            out.append({
                "id": aid,
                "kind": "system.pane",
                "outcome": f"open {title} settings › {et}",
                "provider": f"open:x-apple.systempreferences:{bid}?{anchor}",
                "authority": "human-required",
                "probe": None,
                "x_aliases": sorted({t.lower() for t in titles} | set(terms) | {words(short).lower()}),
                "x_bundle": bid,
                "x_anchor": anchor,
                "x_titles": [t.lower() for t in titles],
                "x_parent": f"system.pane.{slug}",
                "x_note": "Sub-page anchor from Apple's Settings search index "
                          f"({os.path.basename(f)}). Opens the pane at that section; a human "
                          "finishes. hilt cannot observe where it lands; the pane?anchor form was "
                          "confirmed by a human once (Privacy_AllFiles, macOS 26.6.2, 2026-09-23).",
                "x_source": ["settings-searchterms"],
            })
            tally["records"] += 1
    return out


def _vt_desc(vt, enums):
    s = json.dumps(vt)
    if "primitive" in vt:
        return ("primitive:" + str((vt.get("primitive") or {}).get("wrapper", {}).get("typeIdentifier", "")), None)
    for name in re.findall(r'"typeName":\s*"([^"]+)"', s) + re.findall(r'"identifier":\s*"([^"]+)"', s):
        if name in enums:
            return ("enum:" + name, enums[name])
    if "entity" in vt:
        return ("entity:" + ",".join(re.findall(r'"typeName":\s*"([^"]+)"', s)), None)
    return (next(iter(vt.keys()), "unknown"), None)


def scan_intents(bids_by_path):
    files = []
    for pat in [os.path.join(EXT_DIR, "*.appex")] + [os.path.join(r, "*.app") for r in APP_ROOTS]:
        for b in glob.glob(pat):
            f = os.path.join(b, "Contents", "Resources", "Metadata.appintents", "extract.actionsdata")
            if os.path.exists(f):
                files.append((b, f))
    recs, bad, acts, typed = [], 0, 0, 0
    for bundle, f in files:
        try:
            d = json.load(open(f))
        except Exception:
            bad += 1
            continue
        info = read_plist(os.path.join(bundle, "Contents", "Info.plist")) or {}
        bid = info.get("CFBundleIdentifier") or os.path.basename(bundle)
        enums = {}
        for e in d.get("enums") or []:
            cases = [c.get("identifier") for c in e.get("cases", [])]
            enums[e.get("identifier")] = cases
            fq = e.get("fullyQualifiedTypeName", "")
            if fq:
                enums[fq.split(".")[-1]] = cases
        for name, a in (d.get("actions") or {}).items():
            acts += 1
            params = []
            for p in a.get("parameters") or []:
                t, cases = _vt_desc(p.get("valueType") or {}, enums)
                if cases is not None or p.get("dynamicOptionsSupport"):
                    typed += 1
                params.append({"name": p.get("name"), "type": t, "optional": bool(p.get("isOptional")),
                               "enum": cases, "dynamic_options": bool(p.get("dynamicOptionsSupport")),
                               "title": (p.get("title") or {}).get("key")})
            title = (a.get("title") or {}).get("key") or words(name)
            recs.append({
                "id": f"intent.{bid}.{name}",
                "kind": "system.intent",
                "outcome": title,
                "provider": f"appintent:{bid}:{name}",
                "authority": "human-required",
                "probe": None,
                "x_params": params,
                "x_aliases": [title.lower()],
                "x_opens_app": bool(a.get("openAppWhenRun")),
                "x_attribution": a.get("attributionBundleIdentifier"),
                "x_bundle": bid,
                "x_note": "Described from Apple's own App Intents manifest. No public shell door "
                          "invokes an App Intent, so this record is describe-only: route to its "
                          "pane, a defaults/CLI setting, or a user Shortcut that wraps it.",
                "x_source": ["appintents"],
            })
    return recs, {"count": acts, "denominator": None, "unit": "App Intents actions",
                  "bundles": len(files), "unreadable": bad, "params_enum_or_dynamic": typed}


def scan_apps(bids):
    paths = set()
    for r in APP_ROOTS:
        paths.update(glob.glob(os.path.join(r, "*.app")))
        paths.update(glob.glob(os.path.join(r, "*", "*.app")))  # vendor folders, one level
    paths = {p for p in paths if ".app/" not in p[:-4]}  # never a helper inside another bundle
    by_bid, no_bid = {}, 0
    for p in sorted(paths):
        info = read_plist(os.path.join(p, "Contents", "Info.plist")) or {}
        bid = info.get("CFBundleIdentifier")
        if not bid:
            no_bid += 1
            continue
        name = info.get("CFBundleDisplayName") or info.get("CFBundleName") or os.path.basename(p)[:-4]
        bg = bool(info.get("LSUIElement") in (True, "1", 1) or info.get("LSBackgroundOnly") in (True, "1", 1))
        by_bid.setdefault(bid, {"name": os.path.basename(p)[:-4], "display": name, "paths": [],
                                "background": bg})["paths"].append(p)
    recs = []
    # Two apps with ONE name (Apple Messages and the Google Messages Chrome app, 2026-09-28):
    # how often each is used decides which "open messages" means. Spotlight's own counters,
    # read only for the colliding names; absent (Spotlight off) means no preference.
    by_name = {}
    for bid, a in by_bid.items():
        by_name.setdefault(a["name"].lower(), []).append(bid)
    use = {}
    for bids_ in by_name.values():
        if len(bids_) > 1:
            for b in bids_:
                rc, out, _ = sh(["mdls", "-name", "kMDItemUseCount", "-name", "kMDItemLastUsedDate", by_bid[b]["paths"][0]], 5)
                n = re.search(r"kMDItemUseCount\s*=\s*(\d+)", out)
                d = re.search(r"kMDItemLastUsedDate\s*=\s*(\S+)", out)
                use[b] = {"count": int(n.group(1)) if n else None, "last_used": d.group(1) if d else None}
    for bid, a in sorted(by_bid.items()):
        names = {a["name"].lower(), str(a["display"]).lower()} | set(APP_OTHER_NAMES.get(bid, ()))
        recs.append({
            "id": f"app.{bid}",
            "kind": "application.launch",
            "outcome": f"open {a['name']}",
            "provider": f"open -b {bid}",
            "authority": "local",
            "probe": f"lsappinfo info -only pid -app {bid}",
            "x_aliases": sorted(names | {"launch " + n for n in names} | {"open " + n for n in names}),
            "x_bundle": bid,
            "x_paths": a["paths"],
            **({"x_use": use[bid]} if bid in use else {}),
            "x_background": a["background"],
            "x_note": ("verified means a pid, not a window: the desk (Zil's desk_windows) is the "
                       "truth about windows." + (" CONTESTED launch target: several copies share this "
                       "bundle id; open -b picks one by Launch Services' rules." if len(a["paths"]) > 1
                       else "")),
            "x_source": ["apps"],
        })
    return recs, {"count": len(recs), "denominator": len(paths),
                  "unit": "app bundles in standard roots with a bundle id",
                  "without_bundle_id": no_bid}


def scan_sdef(app_recs):
    recs, scriptable, failed = [], 0, 0
    for a in app_recs:
        path = a["x_paths"][0]
        if not glob.glob(os.path.join(path, "Contents", "Resources", "*.sdef")):
            continue
        rc, out, _ = sh(["sdef", path], 30)
        if rc != 0 or not out.strip():
            failed += 1
            continue
        # Entity-expansion guard: drop the whole DOCTYPE (and any internal
        # subset) before parsing, so no entity can be DECLARED. iWork ships a
        # harmless parameter entity there; a hostile dictionary could ship a
        # billion-laughs one. Only the five predefined entities survive.
        out = re.sub(r"<!DOCTYPE[^\[>]*(\[.*?\]\s*)?>", "", out, count=1, flags=re.S)
        try:
            root = ET.fromstring(out)
        except ET.ParseError:
            failed += 1
            continue
        scriptable += 1
        seen = set()
        for suite in root.iter("suite"):
            for c in suite.iter("command"):
                nm = c.get("name")
                if not nm or nm in seen:
                    continue
                seen.add(nm)
                params = []
                dp = c.find("direct-parameter")
                if dp is not None:
                    params.append({"name": "direct", "type": dp.get("type") or "any",
                                   "optional": dp.get("optional") == "yes"})
                for p in c.findall("parameter"):
                    params.append({"name": p.get("name"), "type": p.get("type") or "any",
                                   "optional": p.get("optional") == "yes"})
                recs.append({
                    "id": f"{a['id']}.do.{norm(nm)}",
                    "kind": "application.verb",
                    "outcome": f"{nm} ({a['outcome'][5:]})",
                    "provider": f"osascript:sdef:{a['x_bundle']}:{nm}",
                    "authority": "local",
                    "probe": None,
                    "x_params": params,
                    "x_suite": suite.get("name"),
                    "x_command": nm,
                    "x_description": c.get("description"),
                    "x_aliases": [nm.lower()],
                    "x_bundle": a["x_bundle"],
                    "x_note": "Closed grammar derived from the app's scripting dictionary. "
                              "Only this verb and these parameter types may reach osascript.",
                    "x_source": ["sdef"],
                })
    with_sdef = sum(1 for a in app_recs if glob.glob(os.path.join(a["x_paths"][0], "Contents", "Resources", "*.sdef")))
    return recs, {"count": scriptable, "denominator": with_sdef,
                  "unit": "apps whose shipped .sdef parsed", "verbs": len(recs), "failed": failed}


def networksetup_lists():
    """The devices, hardware ports and services networksetup names on this box.
    These type the `<device name>`-shaped params, so run can accept `en0` and
    refuse anything else rather than hand free text to networksetup."""
    rc, out, _ = sh(["networksetup", "-listallhardwareports"], 20)
    ports = re.findall(r"^Hardware Port: (.+)$", out, re.M)
    devices = re.findall(r"^Device: (\S+)$", out, re.M)
    pairs = re.findall(r"^Hardware Port: (.+)\nDevice: (\S+)$", out, re.M)
    wifi = [d for port, d in pairs if port.strip() in ("Wi-Fi", "AirPort")]
    rc, out, _ = sh(["networksetup", "-listallnetworkservices"], 20)
    services = [l.lstrip("*").strip() for l in out.splitlines()
                if l.strip() and not l.startswith("An asterisk")]
    return {"device name": devices, "networkservice": services,
            "hardwareport or device name": ports + devices, "wifi device": wifi}


def ns_params(args, lists, verb=""):
    """`verb` narrows a generic placeholder where the verb says more than its
    usage text: an -*airport* verb only accepts a Wi-Fi device, so its
    <device name> is typed from the Wi-Fi hardware ports alone."""
    params = []
    for t in re.findall(r"<[^>]+>|\[[^\]]+\]", args):
        nm = re.sub(r"[<>\[\]]", "", t)
        enum, src = None, None
        if nm.strip() in ("on off", "on | off", "on|off"):
            enum, src = ["on", "off"], "derived:networksetup-help"
        elif nm.strip() == "device name" and "airport" in verb.lower() and lists.get("wifi device"):
            enum, src = lists["wifi device"], "derived:networksetup-list(Wi-Fi ports)"
        elif lists.get(nm.strip()):
            enum, src = lists[nm.strip()], "derived:networksetup-list"
        params.append({"name": nm, "optional": t.startswith("["), "type": "string", "enum": enum,
                       "source": src})
    return params


def scan_cli():
    """Apple config CLIs. networksetup's help is parsed into routes and get/set
    pairs; the others are a small authored table of routes whose SHAPE is
    fixed by Apple and whose sudo need was measured, not assumed."""
    recs = []
    present = {c: which(c) for c in EXPECTED_CLIS}
    rc, out, err = sh(["networksetup", "-help"], 20)
    blocks = re.findall(r"Usage: networksetup (-\S+)([^\n]*)\n((?:\t[^\n]*\n?)*)", out + err)
    verbs = {v: (args.strip(), " ".join(l.strip() for l in desc.splitlines()).strip())
             for v, args, desc in blocks}
    lists = networksetup_lists() if verbs else {}
    for v, (args, desc) in sorted(verbs.items()):
        params = ns_params(args, lists, v)
        getter = None
        if v.startswith("-set"):
            g = "-get" + v[4:]
            if g in verbs:
                getter = g
        kind = "system.state" if (v.startswith("-get") or v.startswith("-list")) else "system.cli"
        recs.append({
            "id": f"cli.networksetup.{v[1:].lower()}",
            "kind": kind,
            "outcome": desc[:160] or f"networksetup {v}",
            "provider": f"networksetup {v} {args}".strip(),
            "authority": "local",
            "probe": (f"networksetup {getter}" if getter else None),
            "x_params": params,
            "x_argv": ["networksetup", v],
            "x_probe_argv": ["networksetup", getter] if getter else None,
            "x_probe_params": [p["name"] for p in ns_params(verbs[getter][0], lists, getter)] if getter else None,
            "x_aliases": [v[1:].lower(), words(v[1:]).lower()],
            "x_note": ("Setters may raise an admin prompt depending on the service; unmeasured "
                       "until CUT C exercises them.") if kind == "system.cli" else None,
            "x_source": ["cli:networksetup-help"],
        })
    rows = [
        ("cli.pmset.get", "system.state", "power management settings and state", "pmset -g", "local", []),
        ("cli.pmset.batt", "system.state", "battery charge and power source", "pmset -g batt", "local", []),
        ("cli.pmset.set", "system.cli", "change sleep/power settings", "sudo pmset <arg> <value>", "requires_sudo", []),
        ("cli.scutil.get", "system.state", "read ComputerName, LocalHostName or HostName",
         "scutil --get <pref>", "local", [{"name": "pref", "type": "string", "optional": False,
                                           "enum": ["ComputerName", "LocalHostName", "HostName"]}]),
        ("cli.scutil.set", "system.cli", "rename this Mac (ComputerName/LocalHostName/HostName)",
         "sudo scutil --set <pref> <value>", "requires_sudo", []),
        ("cli.systemsetup", "system.cli", "date/time, sleep, remote login, startup disk (systemsetup)",
         "sudo systemsetup ...", "requires_sudo", []),
        ("cli.tmutil.status", "system.state", "Time Machine backup status", "tmutil status", "local", []),
        ("cli.softwareupdate.list", "system.state", "list available software updates",
         "softwareupdate --list", "local", []),
        ("cli.sw_vers", "system.state", "macOS version and build", "sw_vers", "local", []),
        ("cli.hidutil.list", "system.state", "HID devices and key remapping", "hidutil list", "local", []),
        ("cli.profiles.list", "system.state", "installed configuration profiles", "profiles list", "local", []),
    ]
    for rid, kind, outcome, prov, auth, params in rows:
        # argv is the provider minus its <placeholders>; run appends validated
        # args. A sudo route gets none: there is nothing run may execute.
        argv = None if auth == "requires_sudo" else [w for w in prov.split() if not w.startswith("<")]
        recs.append({"id": rid, "kind": kind, "outcome": outcome, "provider": prov,
                     "authority": auth, "probe": None, "x_params": params, "x_argv": argv,
                     "x_aliases": [outcome.split(" (")[0].lower()],
                     "x_note": ("REQUIRES_SUDO: real, listed, and refused by run — sudo cannot "
                                "prompt from a non-TTY context.") if auth == "requires_sudo" else None,
                     "x_source": ["cli:authored-shape"]})
    diag, dskip = diag_rows(lists)
    recs += diag
    holes = {c: why for c, why in HOLE_CLIS.items() if not which(c)}
    return recs, {"count": sum(1 for p in present.values() if p), "denominator": len(present),
                  "unit": "expected Apple CLIs present",
                  "missing": sorted(c for c, p in present.items() if not p),
                  "networksetup_verbs": len(verbs), "holes": holes,
                  "diagnostics": len(diag), "diagnostics_skipped": dskip}


# Sharing services and the firewall, read WITHOUT root by independent witnesses.
# Measured 2026-09-23 on macOS 26.6.2: `launchctl print system/<label>` exits
# 113 for a service that is not loaded; a loaded label is NOT proof of "on" for
# every service (com.apple.NetworkSharing is loaded with Internet Sharing off),
# so each row names the witnesses that were chosen for it, and two witnesses
# that disagree say so rather than picking one. The ON path of each row is
# unexercised until someone turns the service on (it needs admin in Settings).
STATE_ROWS = [
    ("state.sharing.remote-login", "Remote Login (SSH server) on or off", ["ssh", "sshd", "remote login"],
     [{"launchd": "system/com.openssh.sshd"}, {"listen_tcp": 22}], "Services_RemoteLogin"),
    ("state.sharing.screen-sharing", "Screen Sharing (VNC) on or off", ["vnc", "screen sharing"],
     [{"launchd": "system/com.apple.screensharing"}, {"listen_tcp": 5900}], "Services_ScreenSharing"),
    ("state.sharing.file-sharing", "File Sharing (SMB) on or off", ["smb", "file sharing", "samba"],
     [{"launchd": "system/com.apple.smbd"}, {"listen_tcp": 445}], "Services_PersonalFileSharing"),
    ("state.sharing.remote-apple-events", "Remote Application Scripting (Apple Events) on or off",
     ["remote apple events", "eppc"], [{"launchd": "system/com.apple.AEServer"}, {"listen_tcp": 3031}],
     "Services_RemoteAppleEvent"),
    ("state.sharing.remote-management", "Remote Management (ARD) on or off", ["ard", "remote management"],
     [{"listen_tcp": 3283}], "Services_ARDService"),
    ("state.sharing.printer-sharing", "Printer Sharing on or off", ["printer sharing", "cups sharing"],
     [{"argv": ["cupsctl"], "on": r"^_share_printers=1$", "off": r"^_share_printers=0$"}],
     "Services_PrinterSharing"),
    ("state.sharing.content-caching", "Content Caching on or off", ["content caching", "asset cache"],
     [{"argv": ["AssetCacheManagerUtil", "status"], "on": r"Activated: true", "off": r"Activated: false"}],
     "Services_ContentCaching"),
    ("state.firewall", "application firewall on or off", ["firewall", "alf"],
     [{"argv": ["/usr/libexec/ApplicationFirewall/socketfilterfw", "--getglobalstate"],
       "on": r"is enabled", "off": r"is disabled"}], None),
    ("state.firewall.stealth", "firewall stealth mode on or off", ["stealth mode"],
     [{"argv": ["/usr/libexec/ApplicationFirewall/socketfilterfw", "--getstealthmode"],
       "on": r"stealth mode is on", "off": r"stealth mode is off"}], None),
]


def scan_state(panes):
    by_anchor = {r["x_anchor"]: r["id"] for r in panes if r.get("x_anchor")}
    recs, skipped = [], []
    for rid, outcome, aliases, wit, anchor in STATE_ROWS:
        missing = [w["argv"][0] for w in wit if "argv" in w and not (os.path.isabs(w["argv"][0])
                   and os.access(w["argv"][0], os.X_OK) or which(w["argv"][0]))]
        if missing:
            skipped.append({"id": rid, "why": f"witness CLI absent: {missing}"})
            continue
        fix = by_anchor.get(anchor) if anchor else None
        recs.append({"id": rid, "kind": "system.state", "outcome": outcome,
                     "provider": "witness:" + "+".join(next(iter(w)) for w in wit),
                     "authority": "local", "probe": None, "x_params": [], "x_witness": wit,
                     "x_aliases": aliases, "x_fix": fix,
                     "x_note": "Read-only, no root: each witness answers on/off independently; "
                               "disagreement is reported, never resolved by guessing. Changing it "
                               "needs admin — a human does it in Settings"
                               + (f" (hilt run {fix})." if fix else "."),
                     "x_source": ["state:authored-witnesses"]})
    recs.append({"id": "state.permissions", "kind": "system.state",
                 "outcome": "why an app keeps asking for permission: its privacy (TCC) decisions "
                            "and the Settings pane that fixes each",
                 "provider": "hilt permissions <app>", "authority": "local", "probe": None,
                 "x_params": [{"name": "app", "type": "string", "optional": True, "enum": None,
                               "typed_by": "application.launch", "source": "derived:apps"}],
                 "x_verb": "permissions",
                 "x_aliases": ["permissions", "privacy", "tcc", "keeps asking for permission",
                               "allow prompts", "permission prompts"],
                 "x_note": "Read-only. The app is typed by the index's own apps (name or bundle id); "
                           "no app lists every denial on this Mac.",
                 "x_source": ["tcc"]})
    return recs, {"count": len(recs) - 1, "denominator": len(STATE_ROWS),
                  "unit": "sharing/firewall state rows with their witnesses present", "skipped": skipped}


# Read-only troubleshooting routes: network, Wi-Fi, Bluetooth, USB. Shapes
# are Apple's and were run on this box 2026-09-23 without root. A row whose
# CLI (or system_profiler data type) is absent is skipped and counted, never
# listed. `dev` types a param from networksetup's device list.
DIAG_ROWS = [
    ("cli.ipconfig.getsummary", "interface summary: IP, router, DHCP lease, SSID for a device",
     ["ipconfig", "getsummary"], [("device", "device name", False)], ["interface summary", "dhcp", "ip address"]),
    ("cli.ipconfig.getifaddr", "IPv4 address of a device", ["ipconfig", "getifaddr"],
     [("device", "device name", False)], ["my ip", "ip of"]),
    ("cli.ifconfig", "interface flags, addresses and link status (all, or one device)", ["ifconfig"],
     [("device", "device name", True)], ["interfaces", "link status", "usb ethernet", "usb network"]),
    ("cli.scutil.nwi", "which interface carries traffic now (reachability, primary interface)",
     ["scutil", "--nwi"], [], ["primary interface", "reachability", "network status"]),
    ("cli.scutil.dns", "DNS resolver configuration in effect", ["scutil", "--dns"], [],
     ["dns", "resolver", "name servers"]),
    ("cli.scutil.proxy", "system proxy configuration in effect", ["scutil", "--proxy"], [], ["proxy"]),
    ("cli.route.default", "default route: gateway and outbound interface", ["route", "-n", "get", "default"], [],
     ["gateway", "default gateway", "router", "default route"]),
    ("cli.netstat.routes", "routing table", ["netstat", "-rn"], [], ["routing table", "routes"]),
    ("cli.netstat.listen", "TCP ports listening on this Mac", ["netstat", "-anp", "tcp"], [],
     ["open ports", "listening ports"]),
    ("cli.arp.table", "LAN neighbours seen (ARP table)", ["arp", "-an"], [], ["arp", "lan devices", "neighbours"]),
    ("cli.networkquality", "measure internet throughput and responsiveness (~20 s)", ["networkQuality", "-c"], [],
     ["speed test", "network quality", "bandwidth", "internet speed"]),
    ("cli.sp.wifi", "Wi-Fi hardware, current network, signal, noise, channel and nearby networks (~5 s)",
     ["system_profiler", "-json", "SPAirPortDataType"], [], ["wifi signal", "wifi details", "rssi", "channel", "wifi diagnostics"]),
    ("cli.sp.network", "network services, interfaces and their configuration",
     ["system_profiler", "-json", "SPNetworkDataType"], [], ["network services", "network config"]),
    ("cli.sp.ethernet", "Ethernet adapters (built-in, Thunderbolt, USB) and their drivers",
     ["system_profiler", "-json", "SPEthernetDataType"], [], ["ethernet adapters", "lan adapter", "usb ethernet"]),
    ("cli.sp.bluetooth", "Bluetooth controller state and paired/connected devices",
     ["system_profiler", "-json", "SPBluetoothDataType"], [], ["bluetooth devices", "paired devices", "bluetooth status"]),
    ("cli.sp.usb", "USB devices attached (tree, vendor, speed, power)",
     ["system_profiler", "-json", "SPUSBHostDataType"], [], ["usb devices", "usb", "attached devices", "plugged in", "usb plugged in"]),
    ("cli.sp.thunderbolt", "Thunderbolt / USB4 ports and attached devices",
     ["system_profiler", "-json", "SPThunderboltDataType"], [], ["thunderbolt", "usb4", "dock"]),
    ("cli.sp.firewall", "application firewall settings and per-app rules",
     ["system_profiler", "-json", "SPFirewallDataType"], [], ["firewall rules"]),
    ("cli.sp.volumes", "mounted network volumes (SMB/AFP/NFS)",
     ["system_profiler", "-json", "SPNetworkVolumeDataType"], [], ["network volumes", "mounted shares", "smb mounts"]),
]
# `{state}` in a sudo row's command is its one typed param (on|off). run still
# refuses — sudo cannot prompt from an agent — but the refusal carries the
# exact line for a HUMAN to paste (`human_command`), rendered only from typed
# values, never from free text (default ruled 2026-09-23; spec §11).
SUDO_ROWS = [
    ("cli.wdutil.info", "Wi-Fi diagnostics snapshot (wdutil info)", "sudo wdutil info", ["wdutil"],
     "system.pane.wifi"),
    ("cli.socketfilterfw.set", "turn the application firewall on/off",
     "sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate {state}", ["firewall on"],
     "system.pane.network.firewall"),
    ("cli.socketfilterfw.stealth.set", "turn firewall stealth mode on/off",
     "sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setstealthmode {state}", ["stealth mode on"],
     "system.pane.network.firewall"),
    ("cli.sharing.remote-login.set", "turn Remote Login (SSH) on/off",
     "sudo systemsetup -setremotelogin {state}", ["enable ssh", "turn on ssh"],
     "system.pane.sharing.remotelogin"),
]


# system_profiler, generated from `-listDataTypes` (CUT H slice 8, 2026-10-04). Every type
# was timed on the MBA (tools/fixtures/system-profiler-capture-2026-10-04.txt); the ones
# below are left out BY THAT MEASUREMENT, not by guess: Fonts 8.6 s / 2.0 MB, Logs 3.2 MB,
# Frameworks 0.8 MB with 2,902 items. Everything else answered in under 2 s and 300 KB.
SP_EXCLUDE = {"SPFontsDataType": "8.6 s, 2.0 MB on 2026-10-04", "SPLogsDataType": "3.2 MB of log excerpts",
              "SPFrameworksDataType": "0.8 MB, 2,902 items"}
SP_NAMES = {  # a plain name where the type name is not one
    "ParallelATA": ("Parallel ATA (PATA) devices", ["pata"]), "UniversalAccess": ("accessibility features in use", ["accessibility status"]),
    "SecureElement": ("Secure Element (Apple Pay) status", ["apple pay chip", "secure element"]),
    "Applications": ("every application installed, with version, source and last modified (~2 s)", ["installed apps", "all applications", "app versions", "what apps are installed"]),
    "Camera": ("cameras attached (built-in, USB)", ["camera", "webcam"]), "CardReader": ("SD card reader", ["sd card"]),
    "iBridge": ("the Apple T2/bridge controller", ["t2 chip", "ibridge"]), "DeveloperTools": ("Xcode and SDK versions as the system sees them", ["xcode version profile"]),
    "Diagnostics": ("hardware diagnostics results", ["hardware diagnostics", "apple diagnostics"]), "DisabledSoftware": ("software macOS has disabled (incompatible)", ["disabled software", "incompatible software"]),
    "DiscBurning": ("optical drives", ["dvd drive", "disc burning"]), "Extensions": ("kernel and system extensions loaded (~300 KB)", ["kernel extensions", "system extensions", "kexts"]),
    "FibreChannel": ("Fibre Channel", ["fibre channel"]), "InstallHistory": ("every install: macOS updates, apps, packages, with dates", ["install history", "what was installed when", "package history"]),
    "International": ("language, region and calendar settings", ["language and region profile", "locale"]), "NetworkLocation": ("network locations and their services", ["network locations"]),
    "ManagedClient": ("MDM management state", ["mdm", "managed client", "is this mac managed", "managed by mdm", "is this a managed mac"]), "NVMe": ("NVMe drives: model, capacity, SMART status", ["nvme", "ssd health", "smart status", "drive health"]),
    "PCI": ("PCI devices", ["pci"]), "ParallelSCSI": ("Parallel SCSI", ["scsi"]), "PrefPane": ("legacy preference panes", ["preference panes"]),
    "PrintersSoftware": ("printer drivers and software", ["printer drivers"]), "ConfigurationProfile": ("configuration profiles installed", ["profiles installed", "configuration profiles"]),
    "RawCamera": ("RAW camera formats supported", ["raw camera support"]), "LegacySoftware": ("32-bit / legacy software", ["legacy software", "32 bit apps"]),
    "SAS": ("SAS devices", ["sas"]), "SerialATA": ("SATA devices", ["sata"]), "SPI": ("SPI devices (trackpad, keyboard bus)", ["spi devices"]),
    "SmartCards": ("smart card readers and tokens", ["smart cards", "yubikey", "piv token"]), "StartupItem": ("legacy startup items", ["startup items legacy"]),
    "SyncServices": ("sync services", ["sync services"]), "AppleVirtualPlatform": ("Apple virtualization (VMs)", ["virtual machines", "apple virtual platform"]),
}


def sp_generated(sp_types, taken):
    """One read row per system_profiler data type not already authored, minus the measured
    exclusions. Outcome from SP_NAMES, else the type's own words."""
    recs, skipped = [], []
    for t in sorted(sp_types):
        if t in taken:
            continue
        if t in SP_EXCLUDE:
            skipped.append({"id": t, "why": f"excluded by measurement: {SP_EXCLUDE[t]}"})
            continue
        m = re.fullmatch(r"SP(.+)DataType", t)
        if not m:
            continue
        key = m.group(1)
        name, aliases = SP_NAMES.get(key, (" ".join(w.lower() for w in re.findall(r"[A-Z]+[a-z0-9]*", key)), []))
        slug = re.sub(r"[^a-z0-9]+", "-", key.lower()).strip("-")
        recs.append({"id": f"cli.sp.{slug}", "kind": "system.state", "outcome": f"system_profiler: {name}",
                     "provider": f"system_profiler -json {t}", "authority": "local", "probe": None, "x_params": [],
                     "x_argv": ["system_profiler", "-json", t], "x_aliases": [a.lower() for a in aliases] + [name.split(" (")[0].lower()],
                     "x_note": "Generated from `system_profiler -listDataTypes`; timed on 2026-10-04 "
                               "(tools/fixtures/system-profiler-capture-2026-10-04.txt). An empty list is an answer.",
                     "x_source": ["cli:system_profiler-generated"]})
    return recs, skipped


def diag_rows(lists):
    rc, out, _ = sh(["system_profiler", "-listDataTypes"], 20)
    sp_types = set(out.split()) if rc == 0 else set()
    recs, skipped = [], []
    for rid, outcome, argv, params, aliases in DIAG_ROWS:
        if not which(argv[0]):
            skipped.append({"id": rid, "why": f"{argv[0]} absent"})
            continue
        if argv[0] == "system_profiler" and argv[-1] not in sp_types:
            skipped.append({"id": rid, "why": f"system_profiler has no {argv[-1]} on this OS"})
            continue
        ps = []
        for name, lst, optional in params:
            enum = lists.get(lst)
            if not enum:
                skipped.append({"id": rid, "why": f"no {lst} list to type '{name}'"})
                break
            ps.append({"name": name, "type": "string", "optional": optional, "enum": enum,
                       "source": "derived:networksetup-list"})
        else:
            recs.append({"id": rid, "kind": "system.state", "outcome": outcome,
                         "provider": " ".join(argv + [f"<{p['name']}>" for p in ps]),
                         "authority": "local", "probe": None, "x_params": ps, "x_argv": argv,
                         "x_aliases": aliases, "x_source": ["cli:diagnostics"]})
    for rid, outcome, prov, aliases, fix in SUDO_ROWS:
        ps = ([{"name": "state", "type": "string", "optional": False, "enum": ["on", "off"],
                "source": "authored:apple-usage"}] if "{state}" in prov else [])
        recs.append({"id": rid, "kind": "system.cli", "outcome": outcome,
                     "provider": prov.replace("{state}", "on|off"), "x_command": prov,
                     "authority": "requires_sudo", "probe": None, "x_params": ps, "x_argv": None,
                     "x_aliases": aliases, "x_fix": fix,
                     "x_note": "REQUIRES_SUDO: listed with Apple's exact command, refused by run — sudo "
                               "cannot prompt from an agent. A human runs it, or uses the Settings pane.",
                     "x_source": ["cli:authored-shape"]})
    return recs, skipped


# ---------------------------------------------------------------- native: CoreAudio (backlog N1)
# Apple's PUBLIC C API through ctypes: no third-party tool, no build step
# (Mark 2026-09-24: native first). Verified 2026-09-24 against the out-of-band
# witness `system_profiler SPAudioDataType` (names, defaults, transports).

AUDIO_TRANSPORT = {"bltn": "built-in", "usb ": "usb", "blue": "bluetooth", "bltl": "bluetooth-le",
                   "hdmi": "hdmi", "dprt": "displayport", "airp": "airplay", "virt": "virtual",
                   "aggr": "aggregate", "thun": "thunderbolt", "pci ": "pci", "fwre": "firewire"}
_CA = {}


def _fcc(s4):
    return int.from_bytes(s4.encode("latin1"), "big")


def coreaudio():
    """The loaded frameworks plus call helpers, or None when CoreAudio will
    not load (reported, never read as 'no devices')."""
    if "api" in _CA:
        return _CA["api"]
    import ctypes
    try:
        ca = ctypes.cdll.LoadLibrary("/System/Library/Frameworks/CoreAudio.framework/CoreAudio")
        cf = ctypes.cdll.LoadLibrary("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")
    except OSError:
        _CA["api"] = None
        return None

    class Addr(ctypes.Structure):
        _fields_ = [("sel", ctypes.c_uint32), ("scope", ctypes.c_uint32), ("elem", ctypes.c_uint32)]
    u32, vp = ctypes.c_uint32, ctypes.c_void_p
    ca.AudioObjectGetPropertyDataSize.argtypes = [u32, ctypes.POINTER(Addr), u32, vp, ctypes.POINTER(u32)]
    ca.AudioObjectGetPropertyData.argtypes = [u32, ctypes.POINTER(Addr), u32, vp, ctypes.POINTER(u32), vp]
    ca.AudioObjectSetPropertyData.argtypes = [u32, ctypes.POINTER(Addr), u32, vp, u32, vp]
    cf.CFStringGetCString.argtypes = [vp, ctypes.c_char_p, ctypes.c_long, u32]
    cf.CFStringGetCString.restype = ctypes.c_bool
    cf.CFRelease.argtypes = [vp]
    G = _fcc("glob")

    def size(obj, sel, scope=G):
        n = u32(0)
        a = Addr(_fcc(sel), scope, 0)
        return n.value if ca.AudioObjectGetPropertyDataSize(obj, ctypes.byref(a), 0, None, ctypes.byref(n)) == 0 else None

    def get_u32(obj, sel, scope=G):
        v, n, a = u32(0), u32(4), Addr(_fcc(sel), scope, 0)
        return v.value if ca.AudioObjectGetPropertyData(obj, ctypes.byref(a), 0, None, ctypes.byref(n),
                                                        ctypes.byref(v)) == 0 else None

    def get_str(obj, sel):
        ptr, n, a = vp(), u32(ctypes.sizeof(vp)), Addr(_fcc(sel), G, 0)
        if ca.AudioObjectGetPropertyData(obj, ctypes.byref(a), 0, None, ctypes.byref(n), ctypes.byref(ptr)) \
                or not ptr.value:
            return None
        buf = ctypes.create_string_buffer(1024)
        ok = cf.CFStringGetCString(ptr, buf, 1024, 0x08000100)  # kCFStringEncodingUTF8
        cf.CFRelease(ptr)
        return buf.value.decode("utf-8", "replace") if ok else None

    def ids():
        n = size(1, "dev#")
        if not n:
            return []
        arr = (u32 * (n // 4))()
        nn, a = u32(n), Addr(_fcc("dev#"), G, 0)
        return list(arr) if ca.AudioObjectGetPropertyData(1, ctypes.byref(a), 0, None, ctypes.byref(nn), arr) == 0 else []

    def set_default(sel, dev):
        v, a = u32(dev), Addr(_fcc(sel), G, 0)
        return ca.AudioObjectSetPropertyData(1, ctypes.byref(a), 0, None, 4, ctypes.byref(v))

    _CA["api"] = {"size": size, "get_u32": get_u32, "get_str": get_str, "ids": ids,
                  "set_default": set_default, "OUT": _fcc("outp"), "IN": _fcc("inpt")}
    return _CA["api"]


def audio_devices():
    """Live device list: [{id, name, uid, transport, output, input, default_output, default_input}]."""
    api = coreaudio()
    if api is None:
        return None
    dout, din = api["get_u32"](1, "dOut"), api["get_u32"](1, "dIn ")
    out = []
    for i in api["ids"]():
        t = api["get_u32"](i, "tran")
        code = t.to_bytes(4, "big").decode("latin1") if t is not None else None
        out.append({"id": i, "name": api["get_str"](i, "lnam"), "uid": api["get_str"](i, "uid "),
                    "transport": AUDIO_TRANSPORT.get(code, code),
                    "output": (api["size"](i, "stm#", api["OUT"]) or 0) > 0,
                    "input": (api["size"](i, "stm#", api["IN"]) or 0) > 0,
                    "default_output": i == dout, "default_input": i == din})
    return out


# ---------------------------------------------------------------- status reads (Zil #hilt 141)
# The questions a voice computer gets most. Each is read-only and sub-second, and
# returns `speak` (one sentence Zil can say as is) plus `units` for every numeric
# value, so no caller reads a raw key aloud.

def _say_dur(sec):
    sec = int(sec)
    d, h, m = sec // 86400, sec % 86400 // 3600, sec % 3600 // 60
    parts = [f"{n} {w}{'s' if n != 1 else ''}" for n, w in ((d, "day"), (h, "hour"), (m, "minute")) if n]
    return " ".join(parts[:2]) or "less than a minute"


def status_battery():
    rc, out, _ = sh(["pmset", "-g", "batt"], 5)
    if rc != 0:
        return "failed", None, None, "pmset -g batt did not answer", {}
    return parse_pmset(out)


def parse_pmset(out):
    src = (re.search(r"drawing from '([^']+)'", out) or [None, None])[1]
    m = re.search(r"-InternalBattery-\d+.*?\t(\d+)%;\s*([^;]+);\s*([^\n]*)", out)
    if not m:
        v = {"present": False, "power_source": src, "speak": "This Mac has no battery; it runs on mains power.",
             "units": {}}
        return "query", None, v, "no battery (" + (src or "unknown source") + ")", {}
    pct, state, rest = int(m.group(1)), m.group(2).strip(), m.group(3)
    t = re.search(r"(\d+):(\d+) remaining", rest)
    mins = int(t.group(1)) * 60 + int(t.group(2)) if t else None
    if mins == 0 and state in ("charged", "AC attached"):
        mins = None
    v = {"present": True, "percent": pct, "state": state, "power_source": src,
         "on_battery": src == "Battery Power", "minutes_remaining": mins,
         "estimate": "none yet" if "no estimate" in rest else ("ok" if mins is not None else None),
         "units": {"percent": "%", "minutes_remaining": "min"}}
    left = f", about {_say_dur(mins * 60)} {'to full' if state == 'charging' else 'left'}" if mins else ""
    how = {"charging": "charging", "discharging": "on battery", "charged": "fully charged",
           "finishing charge": "finishing charging",
           "AC attached": "plugged in and holding (not charging)"}.get(state, state)
    v["speak"] = f"Battery is at {pct} percent, {how}{left}."
    text = f"{pct}% {state}" + (f", {mins} min {'to full' if state == 'charging' else 'left'}" if mins else "")
    return "query", None, v, text + f" ({src})", {}


def status_uptime():
    rc, out, _ = sh(["sysctl", "-n", "kern.boottime"], 5)
    m = re.search(r"sec = (\d+)", out)
    if rc != 0 or not m:
        return "failed", None, None, "sysctl kern.boottime unreadable", {}
    boot = int(m.group(1))
    up = int(time.time()) - boot
    v = {"boot_epoch": boot, "boot_local": time.strftime("%Y-%m-%d %H:%M", time.localtime(boot)),
         "uptime_seconds": up, "units": {"uptime_seconds": "s", "boot_epoch": "unix seconds"},
         "speak": f"This Mac has been up {_say_dur(up)}."}
    return "query", None, v, f"up {_say_dur(up)} (booted {v['boot_local']})", {}


def status_disk():
    # The Data volume holds everything the user writes; / is the sealed system
    # snapshot. statvfs counts only truly free blocks: Finder's "available" also
    # counts purgeable space (caches macOS will evict), so it can read higher.
    vol = "/System/Volumes/Data" if os.path.isdir("/System/Volumes/Data") else "/"
    try:
        st = os.statvfs(vol)
    except OSError as e:
        return "failed", None, None, f"statvfs {vol}: {e}", {}
    total, free = st.f_blocks * st.f_frsize / 1e9, st.f_bavail * st.f_frsize / 1e9
    v = {"volume": vol, "total_gb": round(total, 1), "free_gb": round(free, 1),
         "used_percent": round(100 * (1 - free / total)) if total else None,
         "units": {"total_gb": "GB", "free_gb": "GB", "used_percent": "%"},
         "note": "free excludes purgeable space; Finder's 'available' may be higher",
         "speak": f"{round(free):d} gigabytes free of {round(total):d} gigabytes."}
    return "query", None, v, f"{v['free_gb']} GB free of {v['total_gb']} GB ({v['used_percent']}% used) on {vol}", {}


WIFI_JS = r"""ObjC.import("CoreWLAN");
var i = $.CWWiFiClient.sharedWiFiClient.interface;
if (!i || !i.interfaceName) { JSON.stringify({iface: null}); } else {
var c = i.wlanChannel;
JSON.stringify({iface: ObjC.unwrap(i.interfaceName), power: !!i.powerOn, rssi: Number(i.rssiValue),
  noise: Number(i.noiseMeasurement), tx_mbps: Number(i.transmitRate), ssid: ObjC.unwrap(i.ssid) || null,
  channel: c && c.channelNumber ? Number(c.channelNumber) : null, band: c ? Number(c.channelBand) : null}); }"""


def status_wifi():
    # CoreWLAN in-process through the ObjC bridge (not Apple Events: no target
    # app, no Automation grant). RSSI needs no permission; the NETWORK NAME needs
    # Location Services for the host app, and without it macOS returns nothing.
    rc, out, err = sh(["osascript", "-l", "JavaScript", "-e", WIFI_JS], 5)
    try:
        w = json.loads(out)
    except ValueError:
        return "failed", None, None, f"CoreWLAN did not answer: {(err or out).strip()[:120]}", {}
    if not w.get("iface"):
        return "query", None, {"present": False, "speak": "This Mac has no Wi-Fi interface.", "units": {}}, "no Wi-Fi", {}
    assoc = w["power"] and w["rssi"] != 0
    band = {1: "2.4 GHz", 2: "5 GHz", 3: "6 GHz"}.get(w.get("band"))
    sig = (None if not assoc else "excellent" if w["rssi"] >= -55 else "good" if w["rssi"] >= -67
           else "fair" if w["rssi"] >= -75 else "poor")
    v = {"present": True, "power": w["power"], "connected": assoc, "ssid": w["ssid"],
         "ssid_hidden_by": None if w["ssid"] or not assoc else "location-permission",
         "rssi_dbm": w["rssi"] if assoc else None, "noise_dbm": w["noise"] if assoc else None,
         "snr_db": w["rssi"] - w["noise"] if assoc and w["noise"] else None, "signal": sig,
         "tx_rate_mbps": w["tx_mbps"] if assoc else None, "channel": w["channel"] if assoc else None,
         "band": band if assoc else None, "interface": w["iface"],
         "units": {"rssi_dbm": "dBm", "noise_dbm": "dBm", "snr_db": "dB", "tx_rate_mbps": "Mbit/s",
                   "channel": "channel number"}}
    if not w["power"]:
        v["speak"] = "Wi-Fi is off."
    elif not assoc:
        v["speak"] = "Wi-Fi is on but not connected."
    else:
        v["speak"] = (f"Connected to {w['ssid']}" if w["ssid"] else "Connected to Wi-Fi") + \
                     f", {sig} signal" + (f" on {band}" if band else "") + "."
    text = ("off" if not w["power"] else "on, not connected" if not assoc else
            f"{w['ssid'] or '(name hidden: host app lacks Location permission)'} · {w['rssi']} dBm ({sig}) · "
            f"SNR {v['snr_db']} dB · ch {w['channel']} {band or ''} · {w['tx_mbps']:g} Mbit/s")
    return "query", None, v, text, {}


def audio_volume(dev):
    """(volume 0..1 or None, muted or None) for a device's output, via
    AudioToolbox's virtual main volume — the same number the menu-bar slider shows."""
    import ctypes
    try:
        at = ctypes.cdll.LoadLibrary("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")
        ca = ctypes.cdll.LoadLibrary("/System/Library/Frameworks/CoreAudio.framework/CoreAudio")
    except OSError:
        return None, None

    class Addr(ctypes.Structure):
        _fields_ = [("sel", ctypes.c_uint32), ("scope", ctypes.c_uint32), ("elem", ctypes.c_uint32)]
    vol, mute, n = ctypes.c_float(), ctypes.c_uint32(), ctypes.c_uint32(4)
    ok_v = at.AudioHardwareServiceGetPropertyData(dev, ctypes.byref(Addr(_fcc("vmvc"), _fcc("outp"), 0)), 0, None,
                                                  ctypes.byref(n), ctypes.byref(vol)) == 0
    n = ctypes.c_uint32(4)
    ok_m = ca.AudioObjectGetPropertyData(dev, ctypes.byref(Addr(_fcc("mute"), _fcc("outp"), 0)), 0, None,
                                         ctypes.byref(n), ctypes.byref(mute)) == 0
    return (vol.value if ok_v else None), (bool(mute.value) if ok_m else None)


def status_audio():
    devs = audio_devices()
    if devs is None:
        return "failed", None, None, "CoreAudio did not load", {}
    out = next((d for d in devs if d["default_output"]), None)
    inp = next((d for d in devs if d["default_input"]), None)
    vol, muted = audio_volume(out["id"]) if out else (None, None)
    pct = round(vol * 100) if vol is not None else None
    v = {"output": out and {"name": out["name"], "transport": out["transport"]},
         "input": inp and {"name": inp["name"], "transport": inp["transport"]},
         "volume_percent": pct, "muted": muted, "units": {"volume_percent": "%"}}
    if not out:
        v["speak"] = "There is no audio output device."
    else:
        v["speak"] = f"Sound is playing through {out['name']}" + (
            ", muted." if muted else f" at {pct} percent." if pct is not None else
            "; that device has no volume control here.")
    text = (f"output {out['name'] if out else 'none'} [{out['transport'] if out else '-'}] · volume "
            f"{'%d%%' % pct if pct is not None else 'n/a (device has no software volume)'}"
            f"{' MUTED' if muted else ''} · input {inp['name'] if inp else 'none'}")
    return "query", None, v, text, {}


def status_bt_connected():
    ctl, devs = bt_devices()
    if devs is None:
        return "failed", None, None, "system_profiler SPBluetoothDataType unreadable", {}
    con = [{"name": d["name"], "kind": d.get("kind"),
            **{k: v for k, v in d.items() if "battery" in k}} for d in devs if d["connected"]]
    units = dict({k: "%" for d in con for k in d if "battery" in k}, count="devices")
    names = [d["name"] for d in con]
    if ctl.get("power") == "off":
        speak = "Bluetooth is off."
    elif not names:
        speak = "No Bluetooth devices are connected."
    else:
        speak = "Connected: " + (", ".join(names[:-1]) + " and " + names[-1] if len(names) > 1 else names[0]) + "."
    v = {"power": ctl.get("power"), "connected": con, "count": len(con), "units": units, "speak": speak}
    return "query", None, v, (f"bluetooth {ctl.get('power')} · " + (", ".join(
        d["name"] + "".join(f" {k}={x}%" for k, x in d.items() if "battery" in k) for d in con) or "nothing connected")), {}


DND_DB = os.environ.get("HILT_DND_DB") or os.path.expanduser("~/Library/DoNotDisturb/DB")


def status_focus():
    # PRIVATE files of the Focus daemon, read-only, and behind Full Disk Access.
    # Two witnesses: Assertions.json holds a Focus someone TURNED ON (Control
    # Center, a Shortcut, a paired device); ModeConfigurations.json holds each
    # mode's schedule, from which "in its scheduled window now" is derived.
    # Smart activations (sleep, driving, location, app) are not visible here.
    try:
        a = json.load(open(os.path.join(DND_DB, "Assertions.json")))
        mc = json.load(open(os.path.join(DND_DB, "ModeConfigurations.json")))
    except PermissionError:
        raise Refusal("permission", "the Focus database needs Full Disk Access for the app hosting hilt "
                      "(`hilt setup`); without it Focus is UNKNOWN, not off.", fix="Privacy_AllFiles")
    except (OSError, ValueError) as e:
        return "failed", None, None, f"Focus database unreadable: {e}", {}
    modes = ((mc.get("data") or [{}])[0].get("modeConfigurations") or {})
    name = lambda mid: ((modes.get(mid) or {}).get("mode") or {}).get("name") or mid
    manual = []
    for rec in ((a.get("data") or [{}])[0].get("storeAssertionRecords") or []):
        mid = (rec.get("assertionDetails") or {}).get("assertionDetailsModeIdentifier")
        if mid:
            manual.append(name(mid))
    now = time.localtime()
    mins = now.tm_hour * 60 + now.tm_min
    scheduled, schedules = [], []
    for mid, cfg in modes.items():
        for t in ((cfg.get("triggers") or {}).get("triggers") or []):
            if t.get("class") != "DNDModeConfigurationScheduleTrigger" or t.get("enabledSetting") != 2:
                continue
            st = t["timePeriodStartTimeHour"] * 60 + t["timePeriodStartTimeMinute"]
            en = t["timePeriodEndTimeHour"] * 60 + t["timePeriodEndTimeMinute"]
            every_day = t.get("timePeriodWeekdays") == 127
            schedules.append({"mode": name(mid), "from": "%02d:%02d" % divmod(st, 60), "to": "%02d:%02d" % divmod(en, 60),
                              "every_day": every_day})
            inside = (st <= mins < en) if st < en else (mins >= st or mins < en)
            if inside and every_day:
                scheduled.append(name(mid))
    active = manual or scheduled
    v = {"on": bool(active), "manual": manual, "scheduled_now": scheduled, "schedules": schedules,
         "not_visible": "smart activations (sleep, driving, location, app) and schedules on some days only",
         "units": {}}
    v["speak"] = (f"{active[0]} is on" + (" by schedule" if not manual else "") + "." if active
                  else "Focus is off.")
    text = ("ON: " + ", ".join(manual + [f"{s} (scheduled)" for s in scheduled]) if active else "off") + (
        " · schedules: " + ", ".join(f"{s['mode']} {s['from']}-{s['to']}" for s in schedules) if schedules else "")
    return "query", None, v, text, {}


def status_brightness():
    # PRIVATE DisplayServices, read-only (same class as the IOHID thermal read
    # Mark approved 2026-09-26). Built-in panels only; an external display's
    # brightness lives in its own firmware (DDC) and is not read here.
    import ctypes
    try:
        ds = ctypes.cdll.LoadLibrary("/System/Library/PrivateFrameworks/DisplayServices.framework/DisplayServices")
        cg = ctypes.cdll.LoadLibrary("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics")
    except OSError:
        return "failed", None, None, "DisplayServices did not load", {}
    cg.CGGetOnlineDisplayList.argtypes = [ctypes.c_uint32, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)]
    cg.CGDisplayIsBuiltin.argtypes = [ctypes.c_uint32]
    ds.DisplayServicesGetBrightness.argtypes = [ctypes.c_uint32, ctypes.POINTER(ctypes.c_float)]
    ids, n = (ctypes.c_uint32 * 16)(), ctypes.c_uint32(0)
    cg.CGGetOnlineDisplayList(16, ids, ctypes.byref(n))
    shown = []
    for d in ids[:n.value]:
        b = ctypes.c_float()
        ok = ds.DisplayServicesGetBrightness(d, ctypes.byref(b)) == 0
        shown.append({"display_id": d, "built_in": bool(cg.CGDisplayIsBuiltin(d)),
                      "brightness_percent": round(b.value * 100) if ok else None})
    bi = next((x for x in shown if x["built_in"] and x["brightness_percent"] is not None), None)
    v = {"displays": shown, "built_in_percent": bi and bi["brightness_percent"],
         "units": {"brightness_percent": "%", "built_in_percent": "%"},
         "speak": (f"Screen brightness is {bi['brightness_percent']} percent." if bi else
                   "No built-in screen brightness to read; external displays set their own.")}
    text = " · ".join(f"{'built-in' if x['built_in'] else 'display %d' % x['display_id']}: "
                      f"{'%d%%' % x['brightness_percent'] if x['brightness_percent'] is not None else 'n/a'}"
                      for x in shown) or "no displays online"
    return "query", None, v, text, {}


STATUS_READS = {"status.battery": status_battery, "status.uptime": status_uptime, "status.disk": status_disk,
                "status.wifi": status_wifi, "status.audio": status_audio, "status.bluetooth": status_bt_connected,
                "status.focus": status_focus, "status.brightness": status_brightness}

HOST_PARAM = {"name": "host", "type": "string", "optional": True, "enum": None, "dynamic_options": True,
              "typed_by": "tailnet.mac", "source": "derived:tailscale status (online macOS peers)"}
MODEL_WORDS = {"macbook", "mac", "mini", "imac", "studio", "air", "pro", "max"}
MODEL_CASE = {"macbook": "MacBook", "imac": "iMac", "mac": "Mac"}


def spoken_host(name):
    """'marks-macbook-pro' -> 'MacBook Pro', 'mini-server' -> 'Mini Server': a tailnet
    name as a person says it (owner prefix and trailing numbers dropped)."""
    t = [x for x in re.split(r"[-_. ]+", name.lower()) if x]
    while len(t) > 1 and t[-1].isdigit():
        t.pop()
    if len(t) > 2 and t[0] not in MODEL_WORDS and t[1] in MODEL_WORDS:
        t = t[1:]
    return " ".join(MODEL_CASE.get(x, x.capitalize()) for x in t)


def host_phrases(peer):
    """What a person calls this Mac: its spoken name, the model part of it, and the
    usual abbreviations (mbp, mba, mac mini). Lowercase phrases."""
    sp = spoken_host(peer["name"]).lower()
    out = {sp}
    words_ = sp.split()
    model = " ".join(w for w in words_ if w in MODEL_WORDS)
    if model:
        out.add(model)
    for full, abbr in (("macbook pro", ("mbp",)), ("macbook air", ("mba",)), ("mini", ("mac mini", "mini"))):
        if full in sp:
            out.update(abbr)
    if peer["self"]:
        out.update({"this mac", "this machine", "here"})
    return out


def remote_status(sid, peer):
    """Run a status read ON a tailnet Mac: hilt's own bytes, piped over the same
    trusted-key ssh as thermals, calling ONE allowlisted reader. No hilt install is
    needed there, only /usr/bin/python3 (Xcode or the CLT)."""
    import base64, zlib
    # ASCII-only and ~4x smaller: the remote python reads stdin as ASCII under ssh
    # (no LANG), and the bytes cross a DERP relay.
    packed = base64.b64encode(zlib.compress(open(os.path.realpath(__file__), "rb").read(), 9)).decode()
    script = (f"import base64, json, zlib\nns = {{'__name__': 'hilt_remote'}}\n"
              f"exec(compile(zlib.decompress(base64.b64decode({packed!r})).decode('utf-8'), 'hilt', 'exec'), ns)\n"
              f"try:\n    r = ns['STATUS_READS'][{sid!r}]()\n    print(json.dumps({{'ok': list(r)}}))\n"
              f"except ns['Refusal'] as e:\n    print(json.dumps({{'refused': [e.why, e.detail, e.extra]}}))\n")
    obj, where, err = fixed_script_read(script, peer["name"])
    if obj is None:
        return "failed", None, None, f"no status read from {where}: {err}", {}
    if "refused" in obj:
        why, detail, extra = obj["refused"]
        raise Refusal(why, f"on {peer['name']}: {detail}", host=peer["name"], **extra)
    verdict, before, after, text, extra = obj["ok"]
    if isinstance(after, dict):
        after["where"], after["host"] = where, peer["name"]
        if after.get("speak"):
            after["speak"] = f"{spoken_host(peer['name'])}: {after['speak']}"
    return verdict, before, after, f"{where}: {text}", extra


def status_read(sid, host=None):
    if host:
        peer = resolve_peer(host)
        if not peer["self"]:
            return remote_status(sid, peer)
    return STATUS_READS[sid]()


# Setting Focus: macOS has no public CLI or API for it. Apple's sanctioned door is a
# Shortcut with the "Set Focus" action; hilt runs two a human made ONCE, by these
# names, and verifies by reading Focus back (state.focus). Private writes to the
# Focus daemon stay out (backlog N7: Mark's call).
FOCUS_SHORTCUTS = {"on": "Do Not Disturb On", "off": "Do Not Disturb Off"}
FOCUS_SETUP = ("one-time, in the Shortcuts app: New Shortcut → add the action \"Set Focus\" → "
               "\"Turn Do Not Disturb On until Turned Off\" → name it \"Do Not Disturb On\". Then a second "
               "one: \"Turn Do Not Disturb Off\", named \"Do Not Disturb Off\". hilt runs them by name "
               "and checks the result.")


def focus_shortcut_plist(want):
    """The Set Focus action, as Shortcuts' own file format (a binary plist). Built here,
    signed on THIS Mac at setup, never shipped as signed bytes."""
    import plistlib
    params = {"Enabled": 1 if want == "on" else 0,
              "FocusModes": {"Identifier": "com.apple.donotdisturb.mode.default", "DisplayString": "Do Not Disturb"}}
    if want == "on":
        params["AssertionType"] = "Turned Off"  # "until turned off"
    return plistlib.dumps({
        "WFWorkflowClientVersion": "2607.0.2", "WFWorkflowMinimumClientVersion": 900,
        "WFWorkflowMinimumClientVersionString": "900",
        "WFWorkflowIcon": {"WFWorkflowIconStartColor": 4292093695, "WFWorkflowIconGlyphNumber": 59511},
        "WFWorkflowImportQuestions": [], "WFWorkflowTypes": [], "WFWorkflowInputContentItemClasses": [],
        "WFWorkflowHasShortcutInputVariables": False, "WFQuickActionSurfaces": [],
        "WFWorkflowActions": [{"WFWorkflowActionIdentifier": "is.workflow.actions.dnd.set",
                               "WFWorkflowActionParameters": params}]}, fmt=plistlib.FMT_BINARY)


# ---- the "hilt" bridge Shortcut (Mark 2026-09-30: "go"; one Add click, not one per control).
# Shortcuts is Apple's public door into controls with no CLI. ONE shortcut named "hilt" takes a
# text instruction ("bluetooth on", "brightness 60") and runs the matching action; every caller
# verifies by an independent readback. A shortcut cannot run what it does not contain, so a new
# control means a new BRIDGE_VERSION and one "Replace" click.
BRIDGE_NAME = "hilt"
BRIDGE_VERSION = "hilt-bridge 1"
BRIDGE_ACTIONS = dict(
    [(f"bluetooth {v}", ("is.workflow.actions.bluetooth.set", {"OnValue": v == "on"})) for v in ("on", "off")] +
    [(f"nightshift {v}", ("is.workflow.actions.nightshift.set", {"OnValue": v == "on"})) for v in ("on", "off")] +
    [(f"lowpower {v}", ("is.workflow.actions.lowpowermode.set", {"OnValue": v == "on"})) for v in ("on", "off")] +
    [(f"brightness {n}", ("is.workflow.actions.setbrightness", {"WFBrightness": n / 100.0})) for n in range(0, 101, 10)])


def bridge_plist():
    import plistlib, uuid
    u = lambda: str(uuid.uuid4()).upper()
    text_id = u()
    text_var = {"Type": "Variable", "Variable": {"Value": {"Type": "ActionOutput", "OutputUUID": text_id,
                                                           "OutputName": "Text"},
                                                 "WFSerializationType": "WFTextTokenAttachment"}}
    acts = [{"WFWorkflowActionIdentifier": "is.workflow.actions.detect.text",
             "WFWorkflowActionParameters": {"UUID": text_id, "WFInput": {
                 "Value": {"Type": "ExtensionInput"}, "WFSerializationType": "WFTextTokenAttachment"}}}]

    def when(word, body):
        g = u()
        acts.append({"WFWorkflowActionIdentifier": "is.workflow.actions.conditional", "WFWorkflowActionParameters": {
            "GroupingIdentifier": g, "WFControlFlowMode": 0, "WFCondition": 4,
            "WFConditionalActionString": word, "WFInput": text_var}})
        acts.extend(body)
        acts.append({"WFWorkflowActionIdentifier": "is.workflow.actions.conditional",
                     "WFWorkflowActionParameters": {"GroupingIdentifier": g, "WFControlFlowMode": 2}})
    for word, (ident, params) in BRIDGE_ACTIONS.items():
        when(word, [{"WFWorkflowActionIdentifier": ident, "WFWorkflowActionParameters": dict(params)}])
    vid = u()
    when("version", [
        {"WFWorkflowActionIdentifier": "is.workflow.actions.gettext",
         "WFWorkflowActionParameters": {"UUID": vid, "WFTextActionText": BRIDGE_VERSION}},
        {"WFWorkflowActionIdentifier": "is.workflow.actions.output", "WFWorkflowActionParameters": {
            "WFOutput": {"Value": {"string": "￼", "attachmentsByRange": {"{0, 1}": {
                "Type": "ActionOutput", "OutputUUID": vid, "OutputName": "Text"}}},
                "WFSerializationType": "WFTextTokenString"}}}])
    return plistlib.dumps({
        "WFWorkflowClientVersion": "2607.0.2", "WFWorkflowMinimumClientVersion": 900,
        "WFWorkflowMinimumClientVersionString": "900",
        "WFWorkflowIcon": {"WFWorkflowIconStartColor": 463140863, "WFWorkflowIconGlyphNumber": 59446},
        "WFWorkflowImportQuestions": [], "WFWorkflowTypes": [], "WFQuickActionSurfaces": [],
        "WFWorkflowInputContentItemClasses": ["WFStringContentItem", "WFGenericFileContentItem"],
        "WFWorkflowHasShortcutInputVariables": True, "WFWorkflowActions": acts}, fmt=plistlib.FMT_BINARY)


def bridge_dir():
    d = os.path.join(os.path.dirname(HILT_KNOWN_HOSTS), "shortcuts")
    os.makedirs(d, exist_ok=True)
    return d


def bridge_present():
    rc, out, _ = sh(["shortcuts", "list"], 15)
    return BRIDGE_NAME in [x.strip() for x in out.splitlines()]


def bridge_state():
    """'absent' | 'current' | 'stale:<its answer>': asks the shortcut itself for its version."""
    if not bridge_present():
        return "absent"
    src, dst = os.path.join(bridge_dir(), "bridge-in.txt"), os.path.join(bridge_dir(), "bridge-out.txt")
    open(src, "w").write("version")
    if os.path.exists(dst):
        os.remove(dst)
    sh(["shortcuts", "run", BRIDGE_NAME, "-i", src, "-o", dst], 20)
    got = open(dst, errors="replace").read().strip() if os.path.exists(dst) else ""
    return "current" if got == BRIDGE_VERSION else f"stale:{got or 'no version answer'}"


def bridge_run(word):
    """Run ONE allowlisted instruction through the bridge, or refuse with the fix."""
    if word not in BRIDGE_ACTIONS:
        raise Refusal("bad-enum", f"'{word}' is not a bridge instruction.")
    if not bridge_present():
        raise Refusal("setup-required", "this needs the one-time \"hilt\" Shortcut. Fix: `hilt setup shortcuts` "
                      "(builds and signs it here; a person clicks \"Add Shortcut\" once).",
                      fix_command="hilt setup shortcuts",
                      human_must="click \"Add Shortcut\" once after `hilt setup shortcuts`")
    src = os.path.join(bridge_dir(), "bridge-in.txt")
    open(src, "w").write(word)
    rc, out, err = sh(["shortcuts", "run", BRIDGE_NAME, "-i", src], 30)
    return rc, (err or out).strip()


def setup_bridge(check_only):
    st = bridge_state()
    if st == "current":
        emit({"verdict": "OK", "bridge": BRIDGE_VERSION, "instructions": sorted(BRIDGE_ACTIONS)},
             f"OK the \"{BRIDGE_NAME}\" Shortcut is present and current ({BRIDGE_VERSION}).")
    d = bridge_dir()
    src, out = os.path.join(d, "hilt.unsigned.shortcut"), os.path.join(d, f"{BRIDGE_NAME}.shortcut")
    open(src, "wb").write(bridge_plist())
    rc, o, e = sh(["shortcuts", "sign", "--mode", "people-who-know-me", "--input", src, "--output", out], 60)
    if rc != 0:
        emit({"verdict": "FAILED", "errors": [(e or o).strip()[:200]]}, "FAILED sign: " + (e or o).strip()[:200], 1)
    opened = (not check_only) and sh(["open", out], 15)[0] == 0
    click = "Add Shortcut" if st == "absent" else "Replace"
    human = f"click \"{click}\" in the Shortcuts window, then `hilt setup shortcuts` again to confirm"
    emit({"verdict": "OK", "state_before": st, "file": out, "opened": opened, "human_must": human},
         (f"OPENED for import ({st}) — {human}" if opened else
          f"READY {out} (not opened: check-only) — open it, then {human}"))


def focus_shortcuts_present():
    rc, out, _ = sh(["shortcuts", "list"], 15)
    have = {x.strip() for x in out.splitlines()}
    return {w: n in have for w, n in FOCUS_SHORTCUTS.items()}


def setup_focus(check_only):
    """`hilt setup focus`: build the two Set Focus Shortcuts, sign them here, and open each
    for import. macOS requires a person to click "Add Shortcut" for each: that click is
    the whole human part. Verified afterwards by `hilt run native.focus.set on|off`."""
    have = focus_shortcuts_present()
    missing = [w for w, ok in have.items() if not ok]
    if not missing:
        emit({"verdict": "OK", "shortcuts": FOCUS_SHORTCUTS, "present": have},
             "OK both Focus Shortcuts are present; `hilt run native.focus.set on` sets and verifies.")
    d = os.path.join(os.path.dirname(HILT_KNOWN_HOSTS), "shortcuts")
    os.makedirs(d, exist_ok=True)
    made, opened, errs = [], [], []
    for w in missing:
        src = os.path.join(d, f"{FOCUS_SHORTCUTS[w]}.unsigned.shortcut")
        out = os.path.join(d, f"{FOCUS_SHORTCUTS[w]}.shortcut")
        open(src, "wb").write(focus_shortcut_plist(w))
        rc, o, e = sh(["shortcuts", "sign", "--mode", "people-who-know-me", "--input", src, "--output", out], 60)
        if rc != 0:
            errs.append(f"sign {FOCUS_SHORTCUTS[w]}: {(e or o).strip()[:120]}")
            continue
        made.append(out)
        if not check_only:
            if sh(["open", out], 15)[0] == 0:
                opened.append(out)
    human = ("click \"Add Shortcut\" in each Shortcuts window (" + ", ".join(FOCUS_SHORTCUTS[w] for w in missing) +
             "), then `hilt run native.focus.set on` to verify")
    emit({"verdict": "FAILED" if errs else "OK", "missing": missing, "files": made, "opened": opened,
          "human_must": human if made else None, "errors": errs},
         ("FAILED " + "; ".join(errs)) if errs else
         (f"OPENED {len(opened)} for import — {human}" if opened else
          f"READY {len(made)} signed file(s) in {d} (not opened: check-only) — open each, then {human}"),
         1 if errs else 0)


def focus_now():
    try:
        return status_focus()[2]
    except Refusal:
        return None


def run_focus_set(want):
    name = FOCUS_SHORTCUTS[want]
    rc, out, _ = sh(["shortcuts", "list"], 15)
    if name not in [x.strip() for x in out.splitlines()]:
        raise Refusal("setup-required", f"the Focus Shortcuts are not on this Mac yet. Fix: `hilt setup focus` "
                      "(builds and signs them here; a person clicks \"Add Shortcut\" twice). By hand instead: "
                      + FOCUS_SETUP, shortcut=name, fix_command="hilt setup focus",
                      human_must="click \"Add Shortcut\" twice after `hilt setup focus`")
    before = focus_now()
    rc, out, err = sh(["shortcuts", "run", name], 30)
    if rc != 0:
        return "failed", before, None, f"shortcuts run \"{name}\" exited {rc}: {(err or out).strip()[:200]}", {}
    if before is None:
        return "unverifiable", None, None, ("the Shortcut ran, but Focus cannot be read back here (Full Disk "
                                            "Access for the host app, `hilt setup`)"), {}
    after = poll(focus_now, lambda f: f is not None and f["on"] == (want == "on"), POLL_SECONDS)
    speak = "Do Not Disturb is on." if want == "on" else "Do Not Disturb is off."
    extra = {"already": before["on"] == (want == "on"), "via": f"shortcut: {name}"}
    if after is None or after["on"] != (want == "on"):
        why = (" A daily schedule is in its window, and a schedule's manual override is not visible "
               "in the Focus files." if want == "off" and (after or {}).get("scheduled_now") else "")
        return "mismatched", before, after, f"the Shortcut ran, but Focus reads {'on' if (after or {}).get('on') else 'off'}.{why}", extra
    after = dict(after, speak=speak)
    return "verified", before, after, f"Focus {'on' if want == 'on' else 'off'} ({', '.join(after['manual'] + after['scheduled_now']) or 'none active'})", extra


AUDIO_SEL = {"output": "dOut", "input": "dIn "}


def resolve_audio(direction, a):
    """A device name or uid -> the live device, for THIS direction. The type
    is the device list at call time (devices come and go), never free text."""
    devs = audio_devices()
    if devs is None:
        raise Refusal("native-unavailable", "CoreAudio did not load; nothing was changed.")
    cands = [d for d in devs if d[direction]]
    hit = [d for d in cands if a == d["uid"] or _same_name(d["name"], a)]
    if not hit:  # spoken form, as for Bluetooth: "airpods" -> "Mark’s AirPods Pro", only when UNIQUE
        key = norm(re.sub(r"^(my|the)\s+", "", a.strip(), flags=re.I))
        hit = [d for d in cands if len(key) >= 3 and key in norm(d["name"])]
        if len(hit) > 1:
            raise Refusal("ambiguous", f"'{a}' matches several {direction} devices: "
                          + " | ".join(d["name"] for d in hit) + ". Say which.")
    if len(hit) != 1:
        raise Refusal("bad-enum", f"'{a}' is not one {direction} device on this Mac now; one of: "
                      + " | ".join(d["name"] for d in cands) + " (name or uid).")
    return hit[0]


# ---------------------------------------------------------------- native: Bluetooth (backlog N2/N3)
# List: system_profiler SPBluetoothDataType (no permission needed). Connect /
# disconnect: IOBluetooth's public ObjC API through ONE fixed JXA script —
# its text never varies; the action and the device address arrive as argv
# (the CUT F rule). IOBluetooth is TCC-gated to the RESPONSIBLE app (the
# terminal, or Zil): measured 2026-09-24, the first call raised a Bluetooth
# prompt for iTerm2 and blocked 3 s until Mark clicked Allow. An unattended
# caller would hang there, so every such action is PREFLIGHTED (tcc_preflight).

# open/closeConnection are ASYNCHRONOUS: a script that exits right after the
# call cancels the request (measured 2026-09-24: disconnect and connect both
# returned and nothing changed; with the process kept alive, the AirPods read
# disconnected in 0.5 s). So the script pumps its run loop until the device
# reaches the requested state, or 10 s pass.
BT_JXA = ('ObjC.import("IOBluetooth");ObjC.import("Foundation");'
          'function run(argv){var act=argv[0],addr=argv[1],want=(act==="connect");'
          'var d=$.IOBluetoothDevice.deviceWithAddressString(addr);'
          'if(!d||(d.isNil&&d.isNil()))return JSON.stringify({found:false});'
          # `d.openConnection` is OVERLOADED (openConnection / openConnection: / …): the
          # JXA bridge hands back the FUNCTION, not a call, so nothing connected and the
          # status read None (measured). The explicit selector connected in 164 ms.
          'var st=null;if(act==="connect")st=Number(d.openConnectionWithPageTimeoutAuthenticationRequired($(),16000,false));'
          'else if(act==="disconnect")st=Number(d.closeConnection);'
          'var t0=Date.now();while(Date.now()-t0<10000&&(!!d.isConnected)!==want)'
          '$.NSRunLoop.currentRunLoop.runUntilDate($.NSDate.dateWithTimeIntervalSinceNow(0.25));'
          'return JSON.stringify({found:true,status:st,connected:!!d.isConnected,ms:Date.now()-t0});}')
# Discoverable-device scan (IOBluetoothDeviceInquiry, public): FIXED text,
# the scan length arrives as argv. A delegate collects results; measured
# 2026-09-24: start 0, completed, ~(secs+4) s wall.
# CoreWLAN through the fixed-JXA door (backlog N8). ONE script, argv-only. Measured 2026-10-04 on
# 26A428: a scan takes ~7.7 s and returns SSIDs even when the host lacks Location (the CURRENT
# ssid is what Location hides); `associateToNetwork:password:nil` on a known SECURED network
# disassociates first and then fails -3900 (it does not use the saved credential; macOS
# re-joined on its own ~2 s later). So join is for OPEN networks here; secured ones hand a human
# the networksetup line, where THEY type the password.
WIFI_JXA = ('ObjC.import("CoreWLAN");function run(argv){var c=$.CWWiFiClient.sharedWiFiClient;var i=c.interface;'
            'if(!i||i.isNil())return JSON.stringify({ok:false,why:"no-interface"});var want=argv[1]||null;var t0=Date.now();'
            'var set=i.scanForNetworksWithNameError(want?$(want):$(),$());'
            'if(!set||set.isNil())return JSON.stringify({ok:false,why:"scan-failed"});var arr=set.allObjects,out=[],best=null,bestR=-999;'
            'for(var k=0;k<arr.count;k++){var nw=arr.objectAtIndex(k);var ssid=nw.ssid,ch=nw.wlanChannel,r=Number(nw.rssiValue);'
            'out.push({ssid:(ssid.isNil&&ssid.isNil())?null:ssid.js,rssi:r,channel:ch.isNil()?null:Number(ch.channelNumber),'
            'band:ch.isNil()?null:Number(ch.channelBand),open:Boolean(nw.supportsSecurity(0))});if(r>bestR){bestR=r;best=nw;}}'
            'if(argv[0]==="scan")return JSON.stringify({ok:true,ms:Date.now()-t0,power:Boolean(i.powerOn),networks:out});'
            'if(!best)return JSON.stringify({ok:false,why:"not-scanned"});if(!best.supportsSecurity(0))return JSON.stringify({ok:false,why:"password-required",networks:out});'
            'var err=$();var ok=i.associateToNetworkPasswordError(best,$(),err);'
            'return JSON.stringify({ok:Boolean(ok),ms:Date.now()-t0,channel:Number(best.wlanChannel.channelNumber),rssi:bestR,'
            'error:(err.isNil&&err.isNil())?null:err.localizedDescription.js,code:(err.isNil&&err.isNil())?null:Number(err.code)});}')
BT_INQ = ('ObjC.import("IOBluetooth");ObjC.import("Foundation");var seen={},done=false;'
          'ObjC.registerSubclass({name:"HiltInquiryDelegate",methods:{'
          '"deviceInquiryDeviceFound:device:":{types:["void",["id","id"]],implementation:function(s,d){'
          'seen[ObjC.unwrap(d.addressString)]=d;}},'
          '"deviceInquiryComplete:error:aborted:":{types:["void",["id","int","bool"]],implementation:function(){done=true;}}}});'
          'var DEL=null;'  # the inquiry holds its delegate WEAKLY: unreferenced, it is freed mid-scan and the next callback segfaults (-11, measured)
          'function run(argv){var secs=Number(argv[0])||8;DEL=$.HiltInquiryDelegate.alloc.init;'
          'var inq=$.IOBluetoothDeviceInquiry.inquiryWithDelegate(DEL);inq.inquiryLength=secs;inq.updateNewDeviceNames=true;'
          'var st=Number(inq.start),t0=Date.now(),end=t0+(secs+6)*1000;'
          'while(!done&&Date.now()<end)$.NSRunLoop.currentRunLoop.runUntilDate($.NSDate.dateWithTimeIntervalSinceNow(0.25));'
          'inq.stop;var out=[];for(var a in seen){var d=seen[a];out.push({name:ObjC.unwrap(d.name)||null,address:a,'
          'paired:!!d.isPaired,connected:!!d.isConnected,rssi:Number(d.RSSI)});}'
          'return JSON.stringify({start_status:st,completed:done,found:out,ms:Date.now()-t0});}')
BT_ADDR = re.compile(r"^[0-9A-Fa-f]{2}([-:][0-9A-Fa-f]{2}){5}$")


def bt_devices():
    """(controller, devices) from system_profiler; devices = [{name, address,
    connected, kind, battery...}]. Serial numbers are dropped (not needed)."""
    rc, out, _ = sh(["system_profiler", "-json", "SPBluetoothDataType"], 30)
    try:
        d = json.loads(out)["SPBluetoothDataType"][0]
    except (ValueError, KeyError, IndexError):
        return None, None
    c = d.get("controller_properties") or {}
    ctl = {"power": {"attrib_on": "on", "attrib_off": "off"}.get(c.get("controller_state"), c.get("controller_state")),
           "discoverable": {"attrib_on": "on", "attrib_off": "off"}.get(c.get("controller_discoverable"),
                                                                      c.get("controller_discoverable"))}
    devs = []
    for sec, conn in (("device_connected", True), ("device_not_connected", False)):
        for item in d.get(sec) or []:
            for name, props in item.items():
                svc = props.get("device_services") or ""
                row = {"name": name, "address": props.get("device_address"), "connected": conn,
                       "kind": props.get("device_minorType"),
                       # AirPods show TWICE when connected (measured 2026-09-24): a BLE-only
                       # record ("< BLE >", case battery) beside the classic one that carries
                       # audio. The BLE-only twin is not a connect target.
                       "le_only": bool(re.search(r"<\s*BLE\s*>", svc)),
                       "vendor": props.get("device_vendorID")}
                # RSSI only for a LIVE link: a not-connected record keeps its last value
                # (measured 2026-09-24: classic AirPods sat at -32 for 60 readings over
                # 5 min while the live LE link moved -40..-53).
                if conn and props.get("device_rssi") is not None:
                    row["rssi"] = props["device_rssi"]
                row.update({k[len("device_"):]: v for k, v in props.items() if "battery" in k.lower()})
                devs.append(row)
    return ctl, devs


def mine_nearby(devs):
    """Your paired devices macOS holds a LIVE Bluetooth LE link to while the
    classic link is down — measured 2026-09-24: AirPods Pro disconnected and
    in the case still showed a connected '< BLE >' twin with fresh battery and
    RSSI. macOS knows the device is yours (paired keys), unlike a raw scan.
    HYPOTHESIS until the walk-away test: twin connected <=> in range."""
    out = []
    for d in devs or []:
        if d.get("le_only") and d["connected"]:
            classic = next((c for c in devs if not c.get("le_only") and _same_name(c["name"], d["name"])), None)
            out.append({"name": d["name"], "rssi": d.get("rssi"), "classic_connected": bool(classic and classic["connected"]),
                        "battery": {k: v for k, v in d.items() if k.startswith("battery")},
                        "signal": "macOS LE link (live link = in range; witnessed)"})
    return out


def _same_name(a, b):
    f = lambda x: (x or "").replace("\u2019", "'").lower().strip()
    return f(a) == f(b)


def resolve_bt(a):
    ctl, devs = bt_devices()
    if devs is None:
        raise Refusal("native-unavailable", "system_profiler SPBluetoothDataType did not answer; nothing was changed.")
    devs = [d for d in devs if not d.get("le_only")]  # connect targets are classic devices
    hit = [d for d in devs if (d["address"] or "").lower() == a.lower() or _same_name(d["name"], a)]
    if not hit:  # spoken form: "airpods" -> "Mark’s AirPods Pro", only when UNIQUE
        key = norm(re.sub(r"^(my|the)\s+", "", a.strip(), flags=re.I))
        hit = [d for d in devs if len(key) >= 3 and key in norm(d["name"])]
        if len(hit) > 1:
            raise Refusal("ambiguous", f"'{a}' matches several paired devices: "
                          + " | ".join(d["name"] for d in hit) + ". Say which.")
    if len(hit) != 1 or not BT_ADDR.match(hit[0]["address"] or ""):
        raise Refusal("bad-enum", f"'{a}' is not one paired Bluetooth device on this Mac; one of: "
                      + " | ".join(d["name"] for d in devs) + " (name or address).")
    return hit[0]


def responsible_app():
    """The TCC client macOS most likely charges hilt's privacy requests to.
    1. __CFBundleIdentifier (a GUI app exports it to its children: iTerm2, Zil).
    2. Else walk the ancestry: the first ancestor inside an .app bundle -> its id.
    3. Else a DETACHED binary (parent launchd, e.g. axil-hold from a cargo dir):
       TCC records such clients BY PATH.
    DERIVED from ancestry — macOS's own responsibility record is not readable
    (responsibility_get_pid_responsible_for_pid echoed every pid back, measured
    2026-09-26, so it is not used). None under ssh/launchd with no host."""
    forced = os.environ.get("HILT_HOST")  # "none" = no host app; else the TCC client to assume
    if forced:
        return None if forced == "none" else forced
    bid = os.environ.get("__CFBundleIdentifier")
    if bid:
        return bid
    pid = os.getppid()
    last = None
    for _ in range(40):
        rc, out, _ = sh(["ps", "-o", "ppid=", "-p", str(pid)], 5)
        if rc != 0 or not out.strip():
            break
        ppid = out.strip()
        # The REAL executable path from the kernel (libproc proc_pidpath, public):
        # `ps -o comm` is argv[0], so a holder started by a bare name ("axil-hold")
        # never looked like a path and the walk skipped it (#hilt 76, 2026-09-26).
        comm = pid_path(pid) or ""
        m = re.search(r"^(.*?\.app)/Contents/MacOS/", comm)
        # An .app INSIDE a framework is an interpreter launcher (Xcode's Python.app, id
        # com.apple.python3, under /usr/bin/python3), never a TCC host: keep walking
        # (#hilt 179: `setup reset` from a Zil tab reset python3's Microphone entry).
        if m and ".framework/" in m.group(1):
            m = None
        if m:
            info = read_plist(os.path.join(m.group(1), "Contents", "Info.plist")) or {}
            if info.get("CFBundleIdentifier"):
                return info["CFBundleIdentifier"]
        if comm.startswith("/") and not comm.startswith(("/bin/", "/usr/", "/sbin/", "/System/")):
            last = comm  # a non-system binary in the chain: the detached host candidate
        if int(ppid) <= 1:
            break
        pid = int(ppid)
    # Only an ad-hoc/unsigned detached binary is its own TCC client (cargo builds:
    # axil-hold, orc-daemon are recorded BY PATH). A SIGNED helper belongs to its
    # app (iTermServer-3.7.1 is iTerm2's, measured 2026-09-26): unknown, not a guess.
    return last if last and host_signature(last) in ("adhoc", "unsigned") else None


def pid_path(pid):
    import ctypes
    try:
        lp = ctypes.CDLL("/usr/lib/libproc.dylib")
        buf = ctypes.create_string_buffer(4096)
        n = lp.proc_pidpath(int(pid), buf, 4096)
        return buf.value.decode("utf-8", "replace") if n > 0 else None
    except (OSError, AttributeError, ValueError):
        return None


def host_signature(app):
    """For a PATH host: 'adhoc' means TCC keys its grants to this build's cdhash —
    every rebuild re-prompts (orc-daemon's grants carry the 40-byte cdhash form)."""
    if not app or not app.startswith("/"):
        return None
    rc, out, err = sh(["codesign", "-dv", app], 10)
    txt = out + err
    # `-dv` prints no Authority= lines (only -dvv does): key on the team id instead
    # (iTermServer read as "unsigned" by the Authority test, measured 2026-09-26).
    if "Signature=adhoc" in txt:
        return "adhoc"
    if "not signed" in txt or rc != 0:
        return "unsigned"
    m = re.search(r"^TeamIdentifier=(.+)$", txt, re.M)
    if re.search(r"^Identifier=com\.apple\.", txt, re.M):
        return "signed"  # Apple platform binaries carry no team id
    return "signed" if m and m.group(1).strip() != "not set" else "adhoc"


def tcc_preflight(service, allow_prompt):
    """Refuse BEFORE acting when the responsible app's decision for `service`
    is denied, or undecided (the action would raise a prompt no unattended
    caller can answer). Returns a note for the run row."""
    app = responsible_app()
    if not app:
        return {"responsible": None, "decision": "unknown",
                "note": "no responsible app in the environment; a hidden prompt would hit the timeout"}
    rows, bad = tcc_read()
    mine = [r for r in rows if r["client"] == app and r["service"] == service]
    state = mine[0]["state"] if mine else ("unknown" if len(bad) == len(TCC_DBS) else "undecided")
    pane = ((load().get("tcc_services") or {}).get(service) or {}).get("pane")
    if state == "denied":
        raise Refusal("permission-denied", f"{app} is DENIED {service}; macOS will not ask again. "
                      + (f"Allow it: hilt run {pane}" if pane else "Allow it in Privacy & Security."),
                      responsible=app, fix=pane)
    if state == "undecided" and not allow_prompt:
        raise Refusal("permission-would-prompt", f"{app} has never been asked for {service}: this action "
                      "would raise a macOS prompt, and an unattended caller would hang on it. A human "
                      "at the screen runs `hilt setup` (or reruns with --allow-prompt) once; afterwards "
                      "it runs unattended.",
                      responsible=app, fix=pane)
    return {"responsible": app, "decision": state}


def run_bt(action, arg, allow_prompt):
    dev = resolve_bt(arg)
    pre = tcc_preflight("kTCCServiceBluetoothAlways", allow_prompt)
    want = action == "connect"
    before = {"connected": dev["connected"]}
    already = dev["connected"] == want
    rc, out, err = sh(["osascript", "-l", "JavaScript", "-e", BT_JXA, action, dev["address"]],
                      BT_TIMEOUT)
    if rc == 124:
        return "failed", before, None, (f"IOBluetooth did not answer in {BT_TIMEOUT}s: likely a hidden "
                                        "permission prompt for the responsible app"), {"preflight": pre}
    try:
        res = json.loads(out.strip().splitlines()[-1])
    except (ValueError, IndexError):
        return "failed", before, None, f"osascript exited {rc}: {(err or out).strip()[:200]}", {"preflight": pre}
    if not res.get("found"):
        return "failed", before, None, "IOBluetooth could not find the device by address", {"preflight": pre}

    def read():
        _, ds = bt_devices()
        m = [d for d in (ds or []) if d["address"] == dev["address"]]
        return {"connected": m[0]["connected"] if m else None}
    after = poll(read, lambda st: st["connected"] == want, BT_POLL)
    extra = {"already": already, "preflight": pre, "iokit_status": res.get("status")}
    if after["connected"] != want:
        return "mismatched", before, after, (f"{action} returned {res.get('status')} but {dev['name']} "
                                             f"reads {'connected' if after['connected'] else 'not connected'} "
                                             f"after {BT_POLL:g}s (device off, out of range, or in its case?)"), extra
    return "verified", before, after, f"{dev['name']} {'connected' if want else 'disconnected'}" + (
        " (already)" if already else ""), extra


# ---------------------------------------------------------------- setup (Mark 2026-09-24)
# "hilt really should have an initial run for a user to make sure permissions
# are top notch. If they opt out, they suffer the fate of an 'allow' prompt and
# a hung agent." hilt goes one better on the opt-out: preflight refuses rather
# than hangs. Permissions are charged to the RESPONSIBLE app, so setup primes
# the app it runs under: run it from each host (the terminal, Zil).

SETUP = os.environ.get("HILT_SETUP") or os.path.join(STATE, "hilt", "setup.json")
FDA_SERVICE = "kTCCServiceSystemPolicyAllFiles"
# A harmless, FIXED call that makes macOS ask for a service NOW, while a human
# is watching. A service with no trigger (Full Disk Access never prompts) gets
# its pane opened instead.
TCC_TRIGGER = {"kTCCServiceBluetoothAlways": "bluetooth"}  # core needs -> trigger name

# Named, FIXED prompt triggers. Profile files reference these NAMES only; no
# command text comes from data. Each is a harmless call that makes macOS ask for
# the service NOW while a human watches. Apple Events triggers send a read-only
# query to a target that is ALREADY RUNNING — setup never launches an app or
# opens a window (tests-must-not-disturb-desktop).
# The query must be an event the TARGET answers: `get name` is resolved locally
# from the bundle and raises no prompt (measured 2026-09-25, Finder stayed
# undecided). Each target gets a read-only query only it can answer.
MIC_JXA = ('ObjC.import("Foundation");var done=false;function run(argv){'
           '$.NSBundle.bundleWithPath("/System/Library/Frameworks/AVFoundation.framework").load;'
           'var c=$.NSClassFromString("AVCaptureDevice");if(!c||(c.isNil&&c.isNil()))return "no-class";'
           'var st=Number(c.authorizationStatusForMediaType("soun"));if(argv[0]==="status"||st!==0)return "status:"+st;'
           'c.requestAccessForMediaTypeCompletionHandler("soun",function(g){done=true;});'
           'var e=Date.now()+110000;while(!done&&Date.now()<e)$.NSRunLoop.currentRunLoop.runUntilDate('
           '$.NSDate.dateWithTimeIntervalSinceNow(0.25));return done?"answered":"timeout";}')
# Calendars: EventKit's status is per entity type (0 = events). Not determined (0) is
# the only state that prompts; macOS 14+ grants full access through
# requestFullAccessToEvents (the older requestAccess is deprecated but still answers).
CAL_JXA = ('ObjC.import("Foundation");var done=false;function run(argv){'
           '$.NSBundle.bundleWithPath("/System/Library/Frameworks/EventKit.framework").load;'
           'var c=$.NSClassFromString("EKEventStore");if(!c||(c.isNil&&c.isNil()))return "no-class";'
           'var st=Number(c.authorizationStatusForEntityType(0));if(argv[0]==="status"||st!==0)return "status:"+st;'
           'var s=c.alloc.init;var sel=s.respondsToSelector("requestFullAccessToEventsWithCompletion:")'
           '?"requestFullAccessToEventsWithCompletion":"requestAccessToEntityTypeCompletion";'
           'if(sel==="requestFullAccessToEventsWithCompletion")s.requestFullAccessToEventsWithCompletion(function(g,e){done=true;});'
           'else s.requestAccessToEntityTypeCompletion(0,function(g,e){done=true;});'
           'var e=Date.now()+110000;while(!done&&Date.now()<e)$.NSRunLoop.currentRunLoop.runUntilDate('
           '$.NSDate.dateWithTimeIntervalSinceNow(0.25));return done?"answered":"timeout";}')
_AE = lambda app, q: ["osascript", "-e", f'tell application id "{app}" to {q}']
SETUP_TRIGGERS = {
    "bluetooth": {"argv": ["osascript", "-l", "JavaScript", "-e",
                  'ObjC.import("IOBluetooth");function run(){var c=$.IOBluetoothHostController.defaultController;'
                  'return JSON.stringify({power:c?Number(c.powerState):null});}']},
    "ae-systemevents": {"argv": _AE("com.apple.systemevents", "count processes"), "needs_running": "com.apple.systemevents",
                        "launch_ok": True},  # windowless: safe to start
    "ae-finder": {"argv": _AE("com.apple.finder", "count Finder windows"), "needs_running": "com.apple.finder"},
    "ae-terminal": {"argv": _AE("com.apple.Terminal", "count windows"), "needs_running": "com.apple.Terminal"},
    "accessibility": {"argv": ["osascript", "-l", "JavaScript", "-e",
                      'ObjC.import("ApplicationServices");function run(){return String($.AXIsProcessTrustedWithOptions('
                      '$({AXTrustedCheckOptionPrompt:true})));}']},
    "screencapture": {"ctypes": "CGRequestScreenCaptureAccess"},
    # `ObjC.import("AVFoundation")` leaves $.AVCaptureDevice UNDEFINED in JXA (measured
    # 2026-09-27: the old trigger threw and setup reported "prompted" while Zil's mic
    # stayed undecided). Load the bundle and look the class up by name; "soun" is
    # AVMediaTypeAudio's value.
    "microphone": {"argv": ["osascript", "-l", "JavaScript", "-e", MIC_JXA]},
    "calendar": {"argv": ["osascript", "-l", "JavaScript", "-e", CAL_JXA]},
}


def fire_trigger(name):
    """Raise the prompt for a named trigger. Returns a short step note."""
    t = SETUP_TRIGGERS.get(name)
    if not t:
        return f"no trigger {name!r}"
    need = t.get("needs_running")
    if need and app_pid(need) is None:
        if t.get("launch_ok"):
            sh(["open", "-g", "-b", need], 20)  # background, windowless app only
            poll(lambda: app_pid(need), lambda p: p is not None, 5)
        else:
            return f"{need} is not running: open it once, then rerun setup (hilt does not launch it)"
    if t.get("ctypes") == "CGRequestScreenCaptureAccess":
        import ctypes
        try:
            cg = ctypes.cdll.LoadLibrary("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics")
            cg.CGRequestScreenCaptureAccess.restype = ctypes.c_bool
            return "prompted (screen recording): " + ("granted" if cg.CGRequestScreenCaptureAccess() else "not granted yet")
        except (OSError, AttributeError) as e:
            return f"screen capture request unavailable: {e}"
    rc, out, err = sh(t["argv"], 120)
    if rc == 124:
        return "prompted (no answer in 120 s)"
    if rc != 0:  # a broken trigger must never read as "prompted"
        return f"TRIGGER FAILED ({(err or out).strip()[:120]})"
    return "prompted" + (f" ({out.strip()})" if out.strip() else "")


def tcc_needs(idx, profile="core"):
    """[{service, target, why, trigger}]: core is DERIVED from the index; a named
    profile (probes/setup-profiles.json, validated at build) adds to it."""
    core = {FDA_SERVICE: ["hilt permissions (reads TCC.db)", "state.permissions"]}
    for r in idx["records"]:
        if r.get("x_tcc"):
            core.setdefault(r["x_tcc"], []).append(r["id"])
    needs = [{"service": sv, "target": None, "why": "needed by " + ", ".join(ids[:3]) + ("…" if len(ids) > 3 else ""),
              "trigger": TCC_TRIGGER.get(sv), "needed_by": ids} for sv, ids in core.items()]
    if profile != "core":
        needs += [dict(r, needed_by=[f"profile:{profile}"]) for r in (idx.get("setup_profiles") or {}).get(profile, [])]
    return needs


# Grants a RUNNING process only picks up at its next launch: macOS offers "quit and
# reopen" for these (Mark hit it for App Management under Zil, 2026-09-27, and
# chose Later). The database says allowed; the live host does not have it yet.
RELAUNCH_SERVICES = {"kTCCServiceSystemPolicyAppBundles", "kTCCServiceSystemPolicyAllFiles",
                     "kTCCServiceScreenCapture"}


# Grants that follow the SESSION, not the app: a process tree started before the
# grant keeps the old answer. Measured 2026-09-27 (zil@mba + hilt@mba): with
# Developer Tools granted to Zil, a fresh binary's first exec cost 560-1861 ms in a
# pre-grant holder, 2-17 ms in a holder the restarted Zil spawned (Terminal, the
# control: 2-14 ms). Full Disk Access, by contrast, applied to the old holder.
SESSION_SERVICES = {"kTCCServiceDeveloperTool"}


def session_started():
    """Start time of this process tree's root under launchd (the holder / terminal
    session hilt runs in), or None."""
    pid, root = os.getpid(), None
    for _ in range(40):
        rc, out, _ = sh(["ps", "-o", "ppid=", "-p", str(pid)], 5)
        if rc != 0 or not out.strip():
            break
        ppid = int(out.strip())
        if ppid <= 1:
            root = pid
            break
        pid = ppid
    if not root:
        return None
    rc, out, _ = sh(["ps", "-o", "lstart=", "-p", str(root)], 5)
    try:
        return time.mktime(time.strptime(out.strip(), "%a %b %d %H:%M:%S %Y"))
    except ValueError:
        return None


def host_started(app):
    """Epoch start time of the running host app (bundle id), or None."""
    if not app or app.startswith("/"):
        return None
    pid = app_pid(app)
    if not pid:
        return None
    rc, out, _ = sh(["ps", "-o", "lstart=", "-p", str(pid)], 5)
    try:
        return time.mktime(time.strptime(out.strip(), "%a %b %d %H:%M:%S %Y"))
    except ValueError:
        return None


def tcc_modified(app, service, target=None):
    rows, _ = tcc_read()
    m = [r for r in rows if r["client"] == app and r["service"] == service and (target is None or r["target"] == target)]
    if not m or not m[0]["last_modified"]:
        return None
    return time.mktime(time.strptime(m[0]["last_modified"], "%Y-%m-%dT%H:%M:%S"))


# ---- TCC status through Apple's PUBLIC, non-prompting status APIs (spec §37, 2026-10-06).
# macOS 27 sealed the per-user TCC database (even Full Disk Access cannot open it), so the
# database is no longer the first witness. Each API answers for the CALLING process's
# responsible app — the host hilt runs under — in milliseconds, and never raises a prompt.
# Measured on the MBA, Zil host: Finder automation 0 (allowed), System Events / Terminal
# -600 (target not running), Spotify BLOCKED >8 s (hence the per-probe timeout: a hang reads
# unknown, never a wait); AX/CG True; mic 3, bt 3, cal 3, cam/contacts/photos/speech/location 0.
AE_PROBE = ("import ctypes,sys\n"
            "cs=ctypes.cdll.LoadLibrary('/System/Library/Frameworks/CoreServices.framework/CoreServices')\n"
            "class D(ctypes.Structure): _fields_=[('t',ctypes.c_uint32),('h',ctypes.c_void_p)]\n"
            "f=lambda s:int.from_bytes(s.encode(),'big')\n"
            "cs.AECreateDesc.argtypes=[ctypes.c_uint32,ctypes.c_void_p,ctypes.c_long,ctypes.POINTER(D)];cs.AECreateDesc.restype=ctypes.c_int32\n"
            "cs.AEDeterminePermissionToAutomateTarget.argtypes=[ctypes.POINTER(D),ctypes.c_uint32,ctypes.c_uint32,ctypes.c_bool];cs.AEDeterminePermissionToAutomateTarget.restype=ctypes.c_int32\n"
            "b=sys.argv[1].encode();d=D();buf=ctypes.create_string_buffer(b);cs.AECreateDesc(f('bund'),buf,len(b),ctypes.byref(d))\n"
            "print(cs.AEDeterminePermissionToAutomateTarget(ctypes.byref(d),f('****'),f('****'),False))\n")
STATUS_JXA = ('ObjC.import("Foundation");function ld(p){$.NSBundle.bundleWithPath(p).load;}function run(){var o={};'
              'ld("/System/Library/Frameworks/AVFoundation.framework");var av=$.NSClassFromString("AVCaptureDevice");'
              'o.kTCCServiceMicrophone=Number(av.authorizationStatusForMediaType("soun"));o.kTCCServiceCamera=Number(av.authorizationStatusForMediaType("vide"));'
              'ld("/System/Library/Frameworks/CoreBluetooth.framework");o.kTCCServiceBluetoothAlways=Number($.NSClassFromString("CBCentralManager").authorization);'
              'ld("/System/Library/Frameworks/EventKit.framework");var ek=$.NSClassFromString("EKEventStore");'
              'o.kTCCServiceCalendar=Number(ek.authorizationStatusForEntityType(0));o.kTCCServiceReminders=Number(ek.authorizationStatusForEntityType(1));'
              'ld("/System/Library/Frameworks/Contacts.framework");o.kTCCServiceAddressBook=Number($.NSClassFromString("CNContactStore").authorizationStatusForEntityType(0));'
              'ld("/System/Library/Frameworks/Photos.framework");o.kTCCServicePhotos=Number($.NSClassFromString("PHPhotoLibrary").authorizationStatusForAccessLevel(1));'
              'ld("/System/Library/Frameworks/Speech.framework");o.kTCCServiceSpeechRecognition=Number($.NSClassFromString("SFSpeechRecognizer").authorizationStatus);'
              'return JSON.stringify(o);}')
# numeric status -> state, per framework (they do not agree on the numbers)
STATUS_MAP = {"kTCCServiceMicrophone": {0: "undecided", 1: "denied", 2: "denied", 3: "allowed"},
              "kTCCServiceCamera": {0: "undecided", 1: "denied", 2: "denied", 3: "allowed"},
              "kTCCServiceBluetoothAlways": {0: "undecided", 1: "denied", 2: "denied", 3: "allowed"},
              "kTCCServiceCalendar": {0: "undecided", 1: "denied", 2: "denied", 3: "allowed", 4: "allowed"},
              "kTCCServiceReminders": {0: "undecided", 1: "denied", 2: "denied", 3: "allowed", 4: "allowed"},
              "kTCCServiceAddressBook": {0: "undecided", 1: "denied", 2: "denied", 3: "allowed", 4: "allowed"},
              "kTCCServicePhotos": {0: "undecided", 1: "denied", 2: "denied", 3: "allowed", 4: "allowed"},
              "kTCCServiceSpeechRecognition": {0: "undecided", 1: "denied", 2: "denied", 3: "allowed"}}
FDA_WITNESSES = ("~/Library/Safari/Bookmarks.plist", "~/Library/Mail", "~/Library/Messages/chat.db")
_status_cache = {}


def tcc_probe(service, target=None):
    """The host's grant for a service by Apple's own status API — allowed | denied |
    undecided | not-granted (an API that cannot tell denied from undecided) — or None when
    no public API exists (Developer Tools, App Management, Full Disk Access is a file
    witness), the target is not running, or the probe hung (5 s)."""
    if service == "kTCCServiceAppleEvents":
        if not target or not app_pid(target):
            return None  # -600: no verdict for a target that is not running
        try:
            out = subprocess.run([sys.executable, "-c", AE_PROBE, target], capture_output=True, text=True, timeout=5).stdout.strip()
            return {"0": "allowed", "-1743": "denied", "-1744": "undecided"}.get(out)
        except (subprocess.SubprocessError, OSError):
            return None
    if service == "kTCCServiceAccessibility":
        import ctypes
        try:
            ax = ctypes.cdll.LoadLibrary("/System/Library/Frameworks/ApplicationServices.framework/ApplicationServices")
            ax.AXIsProcessTrusted.restype = ctypes.c_bool
            return "allowed" if ax.AXIsProcessTrusted() else "not-granted"
        except (OSError, AttributeError):
            return None
    if service == "kTCCServiceScreenCapture":
        import ctypes
        try:
            cg = ctypes.cdll.LoadLibrary("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics")
            cg.CGPreflightScreenCaptureAccess.restype = ctypes.c_bool
            return "allowed" if cg.CGPreflightScreenCaptureAccess() else "not-granted"
        except (OSError, AttributeError):
            return None
    if service == FDA_SERVICE:
        for w in FDA_WITNESSES:
            w = os.path.expanduser(w)
            if os.path.exists(w) or os.path.isdir(os.path.dirname(w)):
                try:
                    os.listdir(w) if os.path.isdir(w) else open(w, "rb").read(4)
                    return "allowed"
                except PermissionError:
                    return "not-granted"
                except OSError:
                    continue
        return None
    if service in STATUS_MAP:
        if "jxa" not in _status_cache:
            try:
                rc, out, _ = sh(["osascript", "-l", "JavaScript", "-e", STATUS_JXA], 10)
                _status_cache["jxa"] = json.loads(out.strip().splitlines()[-1]) if rc == 0 else {}
            except (ValueError, IndexError):
                _status_cache["jxa"] = {}
        v = _status_cache["jxa"].get(service)
        return STATUS_MAP[service].get(v) if v is not None else None
    return None


def tcc_state(app, service, target=None):
    """allowed | denied | undecided | not-granted | unknown. For THIS host the public status API
    answers first (§37); the database is the second witness, and the only one for OTHER apps.
    `undecided` is a VERDICT (both databases read,
    no row); `unknown` means a database could not be read, so absence proves nothing —
    measured 2026-10-04: with the user DB unreadable (a sandboxed shell), Automation →
    Finder read "undecided" and refused permission-would-prompt while the raw osascript
    ran fine. One unreadable database never reads as "never asked"."""
    # HILT_TCC_PROBE=0: fixtures rule (the suite impersonates hosts via __CFBundleIdentifier; a
    # probe answers for the REAL host — 2026-10-06 it let a trash test move tools/hilt to the Trash)
    if app and app == responsible_app() and os.environ.get("HILT_TCC_PROBE", "1") != "0":
        probed = tcc_probe(service, target)
        if probed is not None:
            return probed
    rows, bad = tcc_read()
    if len(bad) == len(TCC_DBS):
        return "unknown"
    mine = [r for r in rows if r["client"] == app and r["service"] == service
            and (target is None or r["target"] == target)]
    if mine:
        return mine[0]["state"]
    return "unknown" if bad else "undecided"


def quarantine_scan(bins):
    """Each binary on PATH, resolved through symlinks, with its quarantine mark
    read (never removed): [{binary, path, state: quarantined|clear|absent, mark}]."""
    out = []
    for b in bins:
        w = which(b)
        if not w:
            out.append({"binary": b, "path": None, "state": "absent", "mark": None})
            continue
        rp = os.path.realpath(w)
        rc, mark, _ = sh(["xattr", "-p", "com.apple.quarantine", rp], 5)
        q = rc == 0 and bool(mark.strip())
        row = {"binary": b, "path": rp, "state": "quarantined" if q else "clear", "mark": mark.strip()[:40] if q else None}
        if q:
            row["human_command"] = f"xattr -d com.apple.quarantine {shlex.quote(rp)}"
        out.append(row)
    return out


def load_setup_profiles(root, tmap):
    src = os.environ.get("HILT_SETUP_PROFILES") or (root and os.path.join(root, "probes", "setup-profiles.json"))
    try:
        profs = json.load(open(src)).get("profiles", {})
    except (OSError, TypeError, ValueError):
        return {}, {"count": 0, "denominator": None, "unit": "setup profile rows validated",
                    "status": f"no setup profiles at {src}", "rejected": []}
    ok, rejected, total = {}, [], 0
    for name, rows in profs.items():
        if not re.fullmatch(r"[a-z][a-z0-9-]*", name) or name == "core":
            rejected.append({"id": name, "why": "profile names are [a-z0-9-] and `core` is derived"})
            continue
        ok.setdefault(name, [])  # a profile exists even with no TCC rows (it may carry only a quarantine list)
        for r in rows:
            total += 1
            why = None
            if r.get("service") not in tmap:
                why = f"service {r.get('service')!r} is not in probes/tcc.json"
            elif r.get("trigger") is not None and r["trigger"] not in SETUP_TRIGGERS:
                why = f"trigger {r['trigger']!r} is not one of hilt's fixed triggers"
            elif r.get("target") is not None and not re.fullmatch(r"[A-Za-z0-9.-]+", r["target"]):
                why = "target must be a bundle id"
            if why:
                rejected.append({"id": f"{name}:{r.get('service')}:{r.get('target')}", "why": why})
            else:
                if r.get("tier") is not None and r["tier"] not in ("core", "developer", "voice", "devices", "other"):
                    rejected.append({"id": f"{name}:{r.get('service')}:{r.get('target')}",
                                     "why": f"tier {r['tier']!r} is not core|developer|voice|devices|other"})
                    continue
                # a profile may re-tier a service FOR ITS HOST (Zil: Accessibility is core —
                # it cannot tile without it) and give its own `breaks` line
                ok.setdefault(name, []).append({k: r.get(k) for k in ("service", "target", "why", "trigger", "tier", "breaks")})
    qc = json.load(open(src)).get("quarantine_check") or {}
    for name, bins in qc.items():
        if name.startswith("_"):
            continue
        good = [b for b in bins if isinstance(b, str) and re.fullmatch(r"[A-Za-z0-9._-]+", b)]
        rejected += [{"id": f"{name}:quarantine:{b}", "why": "binary must be a bare command name"}
                     for b in bins if b not in good]
        ok.setdefault(f"_quarantine:{name}", good)
    return ok, {"count": sum(len(v) for k, v in ok.items() if not k.startswith("_")), "denominator": total,
                "unit": "setup profile rows validated", "profiles": sorted(k for k in ok if not k.startswith("_")),
                "rejected": rejected}


# ---- CUT H: authored Apple CLI rows (probes/cli.json, spec §25)
CLI_PROBE_KINDS = ("regex", "file", "paired")
# A grant the host app must already hold, checked BEFORE acting (never prompting mid-task):
# Automation to System Events / Finder, for the few rows whose only non-root door is a
# FIXED AppleScript line (restart, shut down, log out, empty trash, eject all).
CLI_PREFLIGHTS = {"ae-systemevents": ("kTCCServiceAppleEvents", "com.apple.systemevents"),
                  "ae-finder": ("kTCCServiceAppleEvents", "com.apple.finder")}
CLI_TYPED_BY = ("diskutil.volume", "tz.zoneinfo", "net.host", "text.filename", "app.running",
                "net.ip", "networksetup.service", "networksetup.device", "launchd.label", "app.process", "text.subsystem",
                "app.bundle", "app.path", "simctl.device", "defaults.domain", "text.token", "net.cidr")
TEXT_TOKEN = re.compile(r"[A-Za-z0-9][A-Za-z0-9._-]{0,120}")
TEXT_SUBSYSTEM = re.compile(r"[A-Za-z0-9][A-Za-z0-9._-]{0,120}")
NET_IP4 = re.compile(r"(25[0-5]|2[0-4]\d|1?\d?\d)(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3}")
NET_IP6 = re.compile(r"[0-9A-Fa-f:]{2,39}")  # a literal with at least one ':'; no zone id, no brackets


def net_cidr(v):
    """A network in CIDR form (IPv4 or IPv6), as TN3179's allowlist keys take it — normalised
    ("192.168.1.70/24" -> "192.168.1.0/24"), else None. Parsed, never pattern-guessed."""
    import ipaddress
    if "/" not in v:
        return None
    try:
        return str(ipaddress.ip_network(v, strict=False))
    except ValueError:
        return None
CLI_BUILTINS = ("home", "uid")  # placeholders hilt fills itself, never from argv
# Strict shapes for the two text-ish types. A value is a hostname/IP or a bare file
# name: no separators, no leading dash, no shell metacharacters — and it travels as
# ONE argv element to the binary, never through a shell.
NET_HOST = re.compile(r"[A-Za-z0-9]([A-Za-z0-9.:-]{0,252})")
TEXT_FILENAME = re.compile(r"[A-Za-z0-9][A-Za-z0-9._ -]{0,79}")
CLI_PLACEHOLDER = re.compile(r"\{([a-z][a-z0-9_]*)(\*(\d+))?\}")  # {dns1} has a digit (bug found 2026-10-06)


def load_cli_authored(root):
    """probes/cli.json rows → records. A row is rejected (listed, never installed)
    when its binary is absent, a placeholder names no typed param, a param is
    untyped, a probe kind or typed_by is not in the closed list, a sudo row has
    no command, or a release row names no detached row."""
    src = os.environ.get("HILT_CLI_SRC") or (root and os.path.join(root, "probes", "cli.json"))
    try:
        rows = json.load(open(src)).get("rows", [])
    except (OSError, TypeError, ValueError):
        return [], {"count": 0, "denominator": None, "unit": "authored CLI rows validated",
                    "status": f"no cli rows at {src}", "rejected": [], "skipped": []}
    recs, rejected, skipped, seen = [], [], [], set()
    detached = {r["id"] for r in rows if r.get("detach")}

    def typed(p):
        if p.get("enum"):
            return True
        if p.get("type") == "integer" and p.get("range"):
            return True
        if p.get("type") == "path" and all(m in PATH_RULES for m in p.get("must") or []):
            return True
        return p.get("typed_by") in CLI_TYPED_BY

    for r in rows:
        rid, kind = r.get("id"), r.get("kind")
        why = None
        params = r.get("params") or []
        argv = r.get("argv") or []
        names = {p.get("name") for p in params}
        used = {m.group(1) for a in argv for m in CLI_PLACEHOLDER.finditer(a)} | \
               {m.group(1) for m in CLI_PLACEHOLDER.finditer(r.get("command") or "")}
        if not rid or not re.fullmatch(r"cli\.[a-z0-9.-]+", rid) or rid in seen:
            why = "id must be unique and cli.<tool>.<verb>"
        elif kind not in ("state", "cli"):
            why = f"kind {kind!r} is not state|cli"
        elif r.get("sudo") and not r.get("command"):
            why = "a sudo row carries `command` (the line a human pastes)"
        elif not r.get("sudo") and not argv and not r.get("release"):
            why = "a row needs argv (or `release`)"
        elif used - names - set(CLI_BUILTINS):
            why = f"placeholders {sorted(used - names - set(CLI_BUILTINS))} name no param"
        elif r.get("ok_rc") is not None and (kind != "state" or not isinstance(r["ok_rc"], list)
                                              or not all(isinstance(x, int) for x in r["ok_rc"]) or 0 not in r["ok_rc"]):
            why = "ok_rc is a list of exit codes including 0, on a state row only"
        elif any(not typed(p) for p in params):
            why = "every param must be typed: enum, integer range, path rules, or a typed_by in " + "|".join(CLI_TYPED_BY)
        elif r.get("probe") and r["probe"].get("kind") not in CLI_PROBE_KINDS:
            why = f"probe kind must be one of {'|'.join(CLI_PROBE_KINDS)}"
        elif r.get("probe", {}).get("kind") == "file" and r["probe"].get("param") not in names:
            why = "a file probe names a path param"
        elif r.get("release") and r["release"] not in detached:
            why = f"release names no detached row ({r.get('release')})"
        elif kind == "state" and (r.get("probe") or r.get("detach")):
            why = "a state row is a read: no probe, no detach"
        elif r.get("before") and not (isinstance(r["before"].get("argv"), list) and r["before"]["argv"]):
            why = "`before` is {argv, ok_rc?}: a read taken before acting and reported"
        elif r.get("preflight") and r["preflight"] not in CLI_PREFLIGHTS:
            why = f"preflight must be one of {'|'.join(CLI_PREFLIGHTS)}"
        elif r.get("confirm") and kind != "cli":
            why = "confirm is for setters only"
        elif r.get("stdin") and not (isinstance(r["stdin"], str) and CLI_PLACEHOLDER.fullmatch(r["stdin"])
                                     and CLI_PLACEHOLDER.fullmatch(r["stdin"]).group(1) in names
                                     and next(pp for pp in params if pp["name"] == CLI_PLACEHOLDER.fullmatch(r["stdin"]).group(1)).get("type") == "path"):
            why = "stdin is `{<path param>}`: a typed path fed to the command's stdin"
        if why:
            rejected.append({"id": rid, "why": why})
            continue
        seen.add(rid)
        binary = (r.get("command") or " ").split()[1] if r.get("sudo") else (argv[0] if argv else None)
        if binary and not (os.path.isabs(binary) and os.access(binary, os.X_OK) or which(binary)):
            skipped.append({"id": rid, "why": f"{binary} absent on this Mac"})
            continue
        ps = [{"name": p["name"], "type": p.get("type", "string"), "optional": bool(p.get("optional")),
               "enum": p.get("enum"), "range": p.get("range"), "must": p.get("must"), "roots": p.get("roots"),
               "typed_by": p.get("typed_by"), "external_only": bool(p.get("external_only")),
               "default_from": p.get("default_from"), "default": p.get("default"), "user_agent_only": bool(p.get("user_agent_only")),
               "source": "authored:cli"} for p in params]
        prov = r["command"] if r.get("sudo") else (" ".join(argv) if argv else f"release {r['release']} (SIGTERM its pid)")
        rec = {"id": rid, "kind": "system.state" if kind == "state" else "system.cli",
               "outcome": r["outcome"], "provider": prov,
               "authority": "requires_sudo" if r.get("sudo") else "local",
               "probe": ((f"{r['probe']['kind']}: " + " ".join(r["probe"]["argv"])
                          + (f" ~ /{r['probe']['expect']}/" + (" absent" if r["probe"].get("negate") else "")
                             if r["probe"]["kind"] == "regex" else "")) if r.get("probe", {}).get("argv") else
                         (f"file: {r['probe']['param']} exists after" if r.get("probe", {}).get("kind") == "file" else None)),
               "x_params": ps, "x_argv": None if r.get("sudo") else (argv or None),
               "x_cli_authored": True, "x_cli_probe": r.get("probe"), "x_detach": bool(r.get("detach")),
               "x_ok_rc": r.get("ok_rc"), "x_situation": r.get("situation"), "x_cli_before": r.get("before"),
               "x_confirm": bool(r.get("confirm")), "x_preflight": r.get("preflight"), "x_stdin": r.get("stdin"),
               "x_release": r.get("release"), "x_undo_text": r.get("undo"),
               "x_irreversible_authored": bool(r.get("irreversible")),
               "x_aliases": [a.lower() for a in r.get("aliases") or []],
               "x_note": r.get("note") or (("REQUIRES_SUDO: listed and refused by run; the refusal carries the exact "
                                             "line for a human.") if r.get("sudo") else None),
               "x_source": ["cli:authored", "fixture:tools/fixtures/cli-capture.txt"]}
        if r.get("sudo"):
            rec["x_command"] = r["command"]
        recs.append(rec)
    return recs, {"count": len(recs), "denominator": len(rows), "unit": "authored CLI rows validated",
                  "rejected": rejected, "skipped": skipped,
                  "reads": sum(1 for x in recs if x["kind"] == "system.state"),
                  "setters": sum(1 for x in recs if x["kind"] == "system.cli" and x["authority"] == "local"),
                  "sudo": sum(1 for x in recs if x["authority"] == "requires_sudo")}


def host_version(app):
    """The host app's version, from its bundle (Launch Services path via the index)."""
    for r in (load().get("records") or []):
        if r["kind"] == "application.launch" and r.get("x_bundle") == app and r.get("x_paths"):
            info = read_plist(os.path.join(r["x_paths"][0], "Contents", "Info.plist")) or {}
            return info.get("CFBundleShortVersionString") or info.get("CFBundleVersion")
    return None


MDM_OVERRIDES = "/Library/Application Support/com.apple.TCC/MDMOverrides.plist"


def mdm_overrides(app):
    """Grants pushed by an MDM PPPC profile live in MDMOverrides.plist (absent on an
    unmanaged Mac — measured on the MBA 2026-09-27, with `profiles list` empty).
    Returns {present, services: {kTCCService…: state}} for THIS host."""
    pl = read_plist(MDM_OVERRIDES) if os.path.exists(MDM_OVERRIDES) else None
    if not isinstance(pl, dict):
        return {"present": False, "path": MDM_OVERRIDES, "services": {}}
    mine = pl.get(app) or {}
    svcs = {}
    for k, v in (mine.items() if isinstance(mine, dict) else []):
        name = k if k.startswith("kTCCService") else "kTCCService" + k
        svcs[name] = "managed"
    return {"present": True, "path": MDM_OVERRIDES, "services": svcs}


def designated_requirement(app_path):
    rc, out, err = sh(["codesign", "-dr", "-", app_path], 10)
    m = re.search(r"designated => (.+)$", out + err, re.M)
    return m.group(1).strip() if m else None


def emit_pppc(idx, app, rows):
    """A PPPC (Privacy Preferences Policy Control) payload for IT, as a plist,
    for this host: identifier + its REAL code requirement + one entry per service
    the profile needs. Services MDM cannot allow (Microphone: deny-only; Screen
    Recording: user-settable) are emitted as Apple allows, and listed in notes."""
    if not app:
        die(2, "REFUSED --pppc: no host app", {"verdict": "REFUSED", "why": "no-responsible-app"})
    if app.startswith("/"):
        ident, itype, path = app, "path", app
    else:
        rec = next((r for r in idx["records"] if r["kind"] == "application.launch" and r.get("x_bundle") == app), None)
        ident, itype, path = app, "bundleID", (rec or {}).get("x_paths", [None])[0]
    req = designated_requirement(path) if path else None
    if not req:
        die(2, f"REFUSED --pppc: no code requirement for {app} (unsigned, or not found)",
            {"verdict": "REFUSED", "why": "no-code-requirement"})
    tmap = idx.get("tcc_services") or {}
    services, notes = {}, []
    for x in rows:
        key = x["service"].replace("kTCCService", "")
        how = (tmap.get(x["service"]) or {}).get("pppc", "unknown")
        entry = {"Identifier": ident, "IdentifierType": itype, "CodeRequirement": req, "StaticCode": False}
        if how == "allow":
            entry["Authorization"] = "Allow"
        elif how == "user-settable":
            entry["Authorization"] = "AllowStandardUserToSetSystemService"
        elif how == "deny-only":
            notes.append(f"{key}: MDM cannot pre-allow it (deny only); the user answers the prompt")
            continue
        else:
            notes.append(f"{key}: PPPC support unknown to hilt; omitted")
            continue
        if x.get("target"):
            rec = next((r for r in idx["records"] if r["kind"] == "application.launch" and r.get("x_bundle") == x["target"]), None)
            treq = designated_requirement(rec["x_paths"][0]) if rec else None
            if not treq:
                notes.append(f"AppleEvents → {x['target']}: target not found here; omitted")
                continue
            entry.update({"AEReceiverIdentifier": x["target"], "AEReceiverIdentifierType": "bundleID",
                          "AEReceiverCodeRequirement": treq})
        services.setdefault(key, []).append(entry)
    payload = {"PayloadType": "com.apple.TCC.configuration-profile-policy", "PayloadVersion": 1,
               "PayloadIdentifier": f"hilt.pppc.{norm(ident)}", "PayloadDisplayName": f"Privacy for {ident}",
               "Services": services}
    text = plistlib.dumps(payload).decode()
    emit({"verdict": "OK", "app": app, "payload": payload, "notes": notes,
          "caveat": "hilt's PPPC capability table is unverified on a managed Mac (pppc_verified false); IT reviews before deploying"},
         text + ("\n<!-- " + " · ".join(notes) + " -->" if notes else ""))


def setup_reset(idx, app, rest):
    """`hilt setup reset <service>` — Apple's supported revoke: `tccutil reset
    <Service> <bundle id>` for THIS host only. Never a blanket reset (no
    bundle = every app), never TCC.db directly. Verified by the decision reading
    back as undecided."""
    tmap = idx.get("tcc_services") or {}
    if not rest:
        die(2, "REFUSED setup reset needs a service, e.g. `hilt setup reset kTCCServiceMicrophone`",
            {"verdict": "REFUSED", "why": "no-service"})
    svc = rest[0] if rest[0].startswith("kTCCService") else "kTCCService" + rest[0]
    if svc not in tmap:
        die(2, f"REFUSED {svc} is not a service hilt knows", {"verdict": "REFUSED", "why": "bad-enum"})
    if not app or app.startswith("/"):
        die(2, "REFUSED setup reset works per BUNDLE ID; this host is " + (app or "unknown")
               + " (tccutil cannot reset a path client)", {"verdict": "REFUSED", "why": "not-a-bundle-host"})
    before = tcc_state(app, svc)
    rc, out, err = sh(["tccutil", "reset", svc.replace("kTCCService", ""), app], 20)
    after = tcc_state(app, svc)
    ok = rc == 0 and after in ("undecided", "unknown")
    emit({"verdict": "verified" if ok else ("failed" if rc else "mismatched"), "service": svc, "app": app,
          "before": before, "after": after, "detail": (out + err).strip()[:200]},
         f"{'VERIFIED' if ok else 'NOT RESET'} {svc} for {app}: {before} -> {after}"
         + ("" if ok else f" ({(out + err).strip()[:160]})"), 0 if ok else (1 if rc else 5))


def cmd_setup(args):
    idx = load()
    app = responsible_app()
    # --pppc is an EXPORT: it must never fire a trigger or open a pane (it did, in the
    # suite, opening Full Disk Access on Mark's screen every run — #hilt 136). HILT_NO_OPEN
    # makes any run check-only too.
    check_only = "--check" in OPTS or "--pppc" in OPTS or "--list" in OPTS or os.environ.get("HILT_NO_OPEN") == "1"
    if args and args[0] == "reset":
        setup_reset(idx, app, args[1:])
    if args and args[0] == "focus":
        setup_focus(check_only)
    if args and args[0] == "shortcuts":
        setup_bridge(check_only)
    profile = args[0] if args else "core"
    known = ["core"] + sorted(k for k in (idx.get("setup_profiles") or {}) if not k.startswith("_"))
    if "--list" in OPTS:
        # The profile catalog, from the index: a desk (Zil) renders its PERMISSIONS
        # view from this, never from a copied list (#hilt 234). `core` is folded into
        # every profile, so each row lists only what the profile ADDS.
        tmap = idx.get("tcc_services") or {}
        profs = []
        for name in known:
            rows = [] if name == "core" else (idx.get("setup_profiles") or {}).get(name, [])
            core_rows = tcc_needs(idx, "core")
            profs.append({"name": name, "adds": [
                {"service": r["service"], "target": r.get("target"),
                 "name": ((tmap.get(r["service"]) or {}).get("name") or r["service"])
                         + (f" → {r['target']}" if r.get("target") else ""),
                 "why": r.get("why"), "prompts": r.get("trigger") is not None} for r in rows],
                "core": [r["service"] for r in core_rows] if name == "core" else "included",
                "quarantine_check": (idx.get("setup_profiles") or {}).get(f"_quarantine:{name}", [])})
        emit({"verdict": "OK", "profiles": profs, "check": "hilt --json setup <name> --check",
              "index": {"hilt_version": idx.get("hilt_version"), "built_at": idx.get("built_at"),
                        "age_secs": int(time.time()) - int(idx.get("built_at") or 0)}},
             "\n".join(f"{p['name']:<8} +{len(p['adds'])} service(s)" + (f", {len(p['quarantine_check'])} binaries checked"
                       if p["quarantine_check"] else "") for p in profs))
    if profile not in known:
        die(2, f"REFUSED setup profile {profile!r} — one of: {', '.join(known)}",
            {"verdict": "REFUSED", "why": "unknown-profile", "profiles": known})
    if not app:
        die(2, "REFUSED setup: no responsible app in the environment (__CFBundleIdentifier). Run it from "
               "the app that will host hilt — a terminal, or Zil — so macOS charges the grants to it.",
            {"verdict": "REFUSED", "why": "no-responsible-app"})
    tmap = idx.get("tcc_services") or {}
    out = []
    opened = []
    for need in sorted(tcc_needs(idx, profile), key=lambda n: n["service"] != FDA_SERVICE):
        svc, tgt = need["service"], need.get("target")
        name = ((tmap.get(svc) or {}).get("name") or svc) + (f" → {tgt}" if tgt else "")
        pane = (tmap.get(svc) or {}).get("pane")
        st = tcc_state(app, svc, tgt)
        step = None
        # A profile run ACTS only on what the profile adds. `core` rows (Full Disk
        # Access + every x_tcc) ride along as report-only: state shown, no trigger,
        # no pane. Mark, 2026-10-02 (zil #hilt 237): FDA is off by default and offered
        # only as an explicit Maintenance (= `core`) setup, because every agent in Zil
        # inherits it; a `voice` run that opened the FDA pane would be the surprise he
        # ruled out. `hilt setup core` is the one run that acts on FDA.
        scope = "adds" if profile == "core" or need["needed_by"] == [f"profile:{profile}"] else "core"
        if scope == "core" and st != "allowed":
            step = "report-only (core; `hilt setup core` acts on it)"
        if st == "unknown":
            why_u = (f"{tgt} is not running: Apple's status API needs the target up (open it once, then rerun)"
                     if svc == "kTCCServiceAppleEvents" and tgt and not app_pid(tgt) else
                     "no public status API for this service, and macOS 27 seals the TCC database (§36/§37)")
            step = (step + "; " if step else "") + "unknown: " + why_u
        if not check_only and st not in ("allowed", "unknown") and scope == "adds":
            if st in ("undecided", "not-granted") and need.get("trigger"):
                step = fire_trigger(need["trigger"])  # a human answers the prompt now
                st = tcc_state(app, svc, tgt)
            if st != "allowed" and pane and not opened:
                # ONE pane per run: a second `open` replaces the first before a
                # human can toggle anything. Rerun setup for the next one.
                sh(["open", idx_pane_url(idx, pane)], 20)
                opened.append(pane)
                step = (step + "; " if step else "") + f"opened {pane}"
            elif st != "allowed" and pane:
                step = (step + "; " if step else "") + "pane next run"
        tm = tmap.get(svc) or {}
        out.append({"service": svc, "target": tgt, "name": name, "state": st, "why": need.get("why"),
                    "tier": need.get("tier") or tm.get("tier", "other"), "breaks": need.get("breaks") or tm.get("breaks"),
                    "needed_by": need["needed_by"], "fix": pane, "trigger": need.get("trigger"), "step": step,
                    "scope": scope})
    started, sess = host_started(app), session_started()
    for x in out:
        mod = tcc_modified(app, x["service"], x.get("target")) if x["state"] == "allowed" else None
        x["pending_relaunch"] = bool(x["service"] in RELAUNCH_SERVICES and started and mod and mod > started)
        x["pending_session_restart"] = bool(x["service"] in SESSION_SERVICES and sess and mod and mod > sess)
    pending = [x for x in out if x["pending_relaunch"] or x["pending_session_restart"]]
    managed = mdm_overrides(app)
    for x in out:
        x["managed_by_profile"] = managed["services"].get(x["service"]) if managed["present"] else False
    if "--pppc" in OPTS:
        emit_pppc(idx, app, out)
    quar = quarantine_scan((idx.get("setup_profiles") or {}).get(f"_quarantine:{profile}", []))
    marked = [q for q in quar if q["state"] == "quarantined"]
    # a non-core profile is judged on what it ADDS; core gaps are reported beside it
    missing = [x for x in out if x["state"] not in ("allowed", "unknown") and x["scope"] == "adds"]
    core_missing = [x for x in out if x["state"] not in ("allowed", "unknown") and x["scope"] == "core"]
    unknown = [x for x in out if x["state"] == "unknown" and x["scope"] == "adds"]
    # UNVERIFIABLE: nothing is KNOWN missing, but some grant could not be read (a database
    # hilt cannot open). Never PARTIAL on an unknown — a desk would send a human to fix
    # something that may already be fine (2026-10-04).
    verdict = ("READY" if not missing and not unknown and not marked and not pending else
               "PENDING-RELAUNCH" if not missing and not unknown and not marked else
               "UNVERIFIABLE" if not missing and not marked and unknown else "PARTIAL")
    row = {"app": app, "ts": int(time.time()), "verdict": verdict, "profile": profile,
           "app_version": host_version(app), "os_build": idx["os"]["build"],
           "services": {x["service"] + (f"→{x['target']}" if x["target"] else ""): x["state"] for x in out}}
    if not check_only:
        try:
            cur = json.load(open(SETUP))
        except (OSError, ValueError):
            cur = {}
        cur[app if profile == "core" else f"{app}#{profile}"] = row
        os.makedirs(os.path.dirname(SETUP), exist_ok=True)
        tmp = SETUP + ".tmp"
        json.dump(cur, open(tmp, "w"), indent=1)
        os.replace(tmp, SETUP)
    lines = [f"{verdict} hilt setup [{profile}] for {app}" + (" (check only)" if check_only else "")]
    sig = host_signature(app)
    if sig in ("adhoc", "unsigned"):
        lines.append(f"  WARNING: host is a {sig}-signed binary matched BY PATH — TCC ties these grants to "
                     "this build's code hash, so a rebuild re-prompts. Sign builds with a stable identity "
                     "(Developer ID, or a self-signed dev certificate) to keep grants across rebuilds.")
    for x in out:
        lines.append(f"  {x['state']:<10} {x['name']:<52} " + (x["why"] or "")[:56]
                     + (f"  [{x['step']}]" if x["step"] else "")
                     + (f"  fix: hilt run {x['fix']}" if x["state"] != "allowed" and x["fix"] else ""))
    for x in pending:
        if x["pending_relaunch"]:
            lines.append(f"  PENDING RELAUNCH: {x['name']} was granted after {app} started; the running app gets it "
                         f"only after quit + reopen")
        if x["pending_session_restart"]:
            lines.append(f"  PENDING SESSION RESTART: {x['name']} was granted after THIS session started; processes "
                         f"here do not get it (new sessions do). Restart this session to apply it.")
    for q in marked:
        lines.append(f"  quarantined {q['binary']:<10} {q['path']}  — Gatekeeper will ask 'open?' when a desk "
                     f"app launches it. Yours to clear: {q['human_command']}")
    if quar and not marked:
        lines.append(f"  quarantine: none of {len([q for q in quar if q['state'] != 'absent'])} agent binaries marked")
    if missing:
        lines.append("  Opted out or pending: those actions REFUSE (never hang) until granted; rerun "
                     "`hilt setup` after toggling the app on in the pane.")
    if core_missing:
        lines.append("  core not acted on here: " + ", ".join(x["name"] for x in core_missing)
                     + " — `hilt setup core` is the run that prompts or opens the pane for those.")
    emit({"verdict": verdict, "app": app, "host_signature": sig, "profile": profile, "services": out, "quarantine": quar,
          "managed": managed, "core_missing": [x["service"] for x in core_missing],
          "unknown": [x["service"] + (f"→{x['target']}" if x.get("target") else "") for x in out if x["state"] == "unknown"],
          "check_only": check_only},
         "\n".join(lines), 0 if verdict == "READY" else 4 if verdict == "UNVERIFIABLE" else 2)


def idx_pane_url(idx, pane_id):
    r = next((r for r in idx["records"] if r["id"] == pane_id), None)
    return r["provider"].split(":", 1)[1] if r else "x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension"


def wifi_scan(name=None):
    rc, out, err = sh(["osascript", "-l", "JavaScript", "-e", WIFI_JXA, "scan"] + ([name] if name else []), 40)
    try:
        return json.loads(out.strip().splitlines()[-1]) if rc == 0 else {"ok": False, "why": f"osascript exited {rc}", "error": (err or out).strip()[:200]}
    except (ValueError, IndexError):
        return {"ok": False, "why": "unparsed", "error": (err or out).strip()[:200]}


def run_wifi_scan():
    r = wifi_scan()
    if not r.get("ok"):
        return "failed", None, r, f"scan did not answer: {r.get('why')} {r.get('error') or ''}".strip(), {}
    nets = {}
    for n in r["networks"]:  # one line per name, its strongest band
        k = n["ssid"] or "(hidden)"
        if k not in nets or n["rssi"] > nets[k]["rssi"]:
            nets[k] = dict(n, bands=sorted({x["band"] for x in r["networks"] if (x["ssid"] or "(hidden)") == k}))
    rows = sorted(nets.values(), key=lambda n: -n["rssi"])
    lines = [f"{'open ' if n['open'] else '     '}{(n['ssid'] or '(hidden)'):<28} {n['rssi']:>4} dBm  ch {n['channel']}"
             + (" (2.4+5 GHz)" if len(n["bands"]) > 1 else " (5 GHz)" if n["band"] == 2 else " (2.4 GHz)") for n in rows]
    speak = (f"{len(rows)} Wi-Fi network{'s' if len(rows) != 1 else ''} nearby" + (f"; strongest {rows[0]['ssid']}." if rows and rows[0]["ssid"] else "."))
    return "query", None, {"networks": rows, "power": r.get("power"), "seconds": round(r["ms"] / 1000, 1),
                           "units": {"rssi": "dBm", "channel": "channel number"}, "speak": speak}, "\n".join(lines) or "no networks seen", {}


def resolve_wifi(a):
    """A scanned network name (case-insensitive). Refused `bad-enum` with the names seen."""
    r = wifi_scan()
    if not r.get("ok"):
        raise Refusal("failed", f"Wi-Fi scan did not answer: {r.get('why')}")
    names = sorted({n["ssid"] for n in r["networks"] if n["ssid"]})
    hit = [n for n in names if n.lower() == a.lower()] or [n for n in names if norm(n) == norm(a)]
    if not hit:
        raise Refusal("bad-enum", f"'{a}' is not a Wi-Fi network in range. Seen: " + ", ".join(names[:10]), networks=names)
    return hit[0]


def run_wifi_join(ssid):
    w = status_wifi()[2]
    dev = (w or {}).get("interface") or "en0"
    rc, out, err = sh(["osascript", "-l", "JavaScript", "-e", WIFI_JXA, "join", ssid], 60)
    try:
        r = json.loads(out.strip().splitlines()[-1])
    except (ValueError, IndexError):
        return "failed", None, None, f"osascript exited {rc}: {(err or out).strip()[:200]}", {}
    if r.get("why") == "password-required":
        raise Refusal("password-required", f"'{ssid}' is secured and hilt never carries a password. A human types it: "
                      f"networksetup -setairportnetwork {dev} {shlex.quote(ssid)} <password>",
                      human_command=f"networksetup -setairportnetwork {dev} {shlex.quote(ssid)} <password>")
    if not r.get("ok"):
        return "failed", None, r, f"associate failed: {r.get('error')} (code {r.get('code')})", {}
    after = poll(lambda: status_wifi()[2], lambda s: s and s.get("connected") and s.get("channel") == r.get("channel"), 15)
    ok = bool(after and after.get("connected") and after.get("channel") == r.get("channel"))
    return ("verified" if ok else "mismatched"), None, dict(after or {}, joined_channel=r.get("channel")), \
        (f"joined {ssid}: connected on channel {r.get('channel')} (the name itself is hidden by Location)" if ok else
         f"associate returned ok but the Mac is {'not connected' if not (after or {}).get('connected') else 'on channel ' + str((after or {}).get('channel'))}, "
         f"not channel {r.get('channel')}"), {}


def run_bt_nearby(secs, allow_prompt):
    pre = tcc_preflight("kTCCServiceBluetoothAlways", allow_prompt)
    rc, out, err = sh(["osascript", "-l", "JavaScript", "-e", BT_INQ, str(secs)], secs + 20)
    if rc == 124:
        return "failed", None, None, "the scan did not return: likely a hidden permission prompt", {"preflight": pre}
    try:
        res = json.loads(out.strip().splitlines()[-1])
    except (ValueError, IndexError):
        return "failed", None, None, f"osascript exited {rc}: {(err or out).strip()[:200]}", {"preflight": pre}
    if res.get("start_status") != 0:
        return "failed", None, None, f"inquiry start returned {res.get('start_status')}", {"preflight": pre}
    _, paired = bt_devices()
    connected = sorted({d["name"] for d in (paired or []) if d["connected"] and not d.get("le_only")})
    mine = mine_nearby(paired)
    found = sorted(res["found"], key=lambda d: -(d.get("rssi") or -999))
    ran = round((res.get("ms") or 0) / 1000, 1)
    # Measured 2026-09-24: one 12 s inquiry reported complete after 2.8 s. A scan
    # that ends early can miss devices; say so rather than let "0 found" stand.
    early = ran < secs * 0.75
    lines = [f"{len(found)} discoverable device(s) in {ran} s of {secs} requested"
             + (" (scan cut short)" if not res.get("completed") else "")
             + (" — ENDED EARLY: absence here is weak evidence; scan again" if early else "")]
    lines += [f"  {d['name'] or '(no name)'} rssi {d['rssi']}" + (" [paired]" if d["paired"] else "") for d in found]
    lines.append("  connected now: " + (", ".join(connected) or "none"))
    lines.append("  yours nearby (live LE link): " + (", ".join(
        f"{m['name']} rssi {m['rssi']}" + (" " + " ".join(f"{k[len('batteryLevel'):] or k}={v}" for k, v in m["battery"].items())
                                          if m["battery"] else "") for m in mine) or "none seen"))
    lines.append("  (only devices in pairing/discoverable mode answer a scan; your paired devices idle nearby "
                 "do not — see `hilt traps bt-idle-paired-invisible`)")
    return "query", None, {"discoverable": found, "connected": connected, "mine_nearby": mine,
                           "completed": res.get("completed"),
                           "seconds": secs, "ran_seconds": ran, "ended_early": early}, "\n".join(lines), {"preflight": pre}


BT_TIMEOUT = 20
BT_POLL = 12.0


# ---------------------------------------------------------------- native: thermal + tailnet fleet
# Mark 2026-09-26: "do it local and tailscale — fleet would be a nice control
# surface for monitoring via ZIL". Temperatures come from Apple's PRIVATE IOKit
# HID sensor API (read-only; Mark approved private reads for this). ONE fixed
# script, run by /usr/bin/python3 locally or piped over ssh to a tailnet Mac:
# no request text ever reaches a shell, nothing is installed remotely.
THERMAL_PY = 'import ctypes, json\nIOK = ctypes.cdll.LoadLibrary("/System/Library/Frameworks/IOKit.framework/IOKit")\nCF = ctypes.cdll.LoadLibrary("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")\nvp = ctypes.c_void_p\nCF.CFStringCreateWithCString.restype = vp; CF.CFStringCreateWithCString.argtypes = [vp, ctypes.c_char_p, ctypes.c_uint32]\nCF.CFNumberCreate.restype = vp; CF.CFNumberCreate.argtypes = [vp, ctypes.c_int, vp]\nCF.CFDictionaryCreate.restype = vp; CF.CFDictionaryCreate.argtypes = [vp, vp, vp, ctypes.c_long, vp, vp]\nCF.CFArrayGetCount.restype = ctypes.c_long; CF.CFArrayGetCount.argtypes = [vp]\nCF.CFArrayGetValueAtIndex.restype = vp; CF.CFArrayGetValueAtIndex.argtypes = [vp, ctypes.c_long]\nCF.CFStringGetCString.restype = ctypes.c_bool; CF.CFStringGetCString.argtypes = [vp, ctypes.c_char_p, ctypes.c_long, ctypes.c_uint32]\nIOK.IOHIDEventSystemClientCreate.restype = vp; IOK.IOHIDEventSystemClientCreate.argtypes = [vp]\nIOK.IOHIDEventSystemClientSetMatching.argtypes = [vp, vp]\nIOK.IOHIDEventSystemClientCopyServices.restype = vp; IOK.IOHIDEventSystemClientCopyServices.argtypes = [vp]\nIOK.IOHIDServiceClientCopyProperty.restype = vp; IOK.IOHIDServiceClientCopyProperty.argtypes = [vp, vp]\nIOK.IOHIDServiceClientCopyEvent.restype = vp; IOK.IOHIDServiceClientCopyEvent.argtypes = [vp, ctypes.c_int64, ctypes.c_int32, ctypes.c_int64]\nIOK.IOHIDEventGetFloatValue.restype = ctypes.c_double; IOK.IOHIDEventGetFloatValue.argtypes = [vp, ctypes.c_int32]\ns = lambda t: CF.CFStringCreateWithCString(None, t.encode(), 0x08000100)\ndef n(v):\n    x = ctypes.c_int32(v); return CF.CFNumberCreate(None, 3, ctypes.byref(x))\nkeys = (vp * 2)(s("PrimaryUsagePage"), s("PrimaryUsage")); vals = (vp * 2)(n(0xff00), n(5))\nkcb = vp.in_dll(CF, "kCFTypeDictionaryKeyCallBacks"); vcb = vp.in_dll(CF, "kCFTypeDictionaryValueCallBacks")\nmatch = CF.CFDictionaryCreate(None, keys, vals, 2, ctypes.addressof(kcb), ctypes.addressof(vcb))\ncl = IOK.IOHIDEventSystemClientCreate(None); IOK.IOHIDEventSystemClientSetMatching(cl, match)\nsvcs = IOK.IOHIDEventSystemClientCopyServices(cl)\nout = []\nfor i in range(CF.CFArrayGetCount(svcs) if svcs else 0):\n    sv = CF.CFArrayGetValueAtIndex(svcs, i)\n    p = IOK.IOHIDServiceClientCopyProperty(sv, s("Product")); name = "?"\n    if p:\n        b = ctypes.create_string_buffer(256)\n        if CF.CFStringGetCString(p, b, 256, 0x08000100): name = b.value.decode()\n    ev = IOK.IOHIDServiceClientCopyEvent(sv, 15, 0, 0)\n    if ev: out.append((name, round(IOK.IOHIDEventGetFloatValue(ev, 15 << 16), 1)))\nprint(json.dumps(out))\n'
HILT_KNOWN_HOSTS = os.path.join(STATE, "hilt", "known_hosts")
# Resource snapshot (Mark 2026-09-27: "feed it up thru to ZIL for any alerting").
# hilt MEASURES; Zil owns thresholds, cadence and alerts. Facts only, plus macOS's
# OWN memory-pressure level. WindowServer is SAMPLED (zil@mba, #hilt 117: one
# reading swings ±10; top's first sample is always 0.0 and is dropped). Memory is
# grouped by the OUTERMOST .app, so Chrome's helpers count as Chrome (and are
# broken out by helper type). Blame is proven by EXCLUSION (quit one thing, re-read),
# never by inspection — this is evidence, not a verdict.
RESOURCES_PY = '\nimport collections, json, re, subprocess, time\ndef run(a, t=20):\n    try: return subprocess.run(a, capture_output=True, text=True, timeout=t).stdout\n    except Exception: return ""\napps = collections.defaultdict(lambda: {"rss_mb": 0.0, "cpu": 0.0, "procs": 0})\nchrome = collections.defaultdict(lambda: {"rss_mb": 0.0, "cpu": 0.0, "procs": 0})\nfor line in run(["ps", "-axo", "rss=,pcpu=,comm="]).splitlines():\n    p = line.split(None, 2)\n    if len(p) < 3: continue\n    rss, cpu, comm = int(p[0]) / 1024.0, float(p[1]), p[2].strip()\n    m = re.match(r"^(.*?\\.app)/", comm)   # the OUTERMOST .app owns its helpers\n    key = m.group(1).rsplit("/", 1)[-1][:-4] if m else comm.rsplit("/", 1)[-1]\n    # a binary named by its version (.../claude/versions/2.1.282) belongs to the tool owning\n    # the versions/ dir: the MBP showed "2.1.282" 1.22 GB as its own app (2026-09-27)\n    if re.fullmatch(r"[\\d.]+", key):\n        vm = re.search(r"/([^/]+)/versions/[^/]+$", comm)\n        key = vm.group(1) if vm else key\n    a = apps[key]; a["rss_mb"] += rss; a["cpu"] += cpu; a["procs"] += 1\n    if key == "Google Chrome":\n        h = re.search(r"Helper \\(([^)]+)\\)", comm)\n        part = h.group(1) if h else ("Helper" if "Helper" in comm else "browser")\n        c = chrome[part]; c["rss_mb"] += rss; c["cpu"] += cpu; c["procs"] += 1\nws = {"cpu_samples": [], "rss": None}\npid = run(["pgrep", "-x", "WindowServer"]).strip().split("\\n")[0]\nif pid:\n    rows = [l.split() for l in run(["top", "-l", "4", "-s", "1", "-pid", pid, "-stats", "pid,cpu,mem"], 30).splitlines()\n            if re.match(r"^\\s*" + pid + r"\\s", l)]\n    ws["cpu_samples"] = [float(r[1]) for r in rows[1:]]   # top\'s FIRST sample is always 0.0\n    ws["rss"] = rows[-1][2] if rows else None\nlvl = run(["sysctl", "-n", "kern.memorystatus_vm_pressure_level"]).strip()\nsw = run(["sysctl", "-n", "vm.swapusage"])\nm = re.search(r"used = ([\\d.]+)M", sw); t = re.search(r"total = ([\\d.]+)M", sw)\nmem = int(run(["sysctl", "-n", "hw.memsize"]).strip() or 0)\nr2 = lambda d: {k: round(v, 1) if isinstance(v, float) else v for k, v in d.items()}\ntop = sorted(apps.items(), key=lambda kv: -kv[1]["rss_mb"])\nprint(json.dumps({"ts": int(time.time()),\n    "memory": {"ram_gb": round(mem / 2**30), "pressure_level": {"1": "normal", "2": "warn", "4": "critical"}.get(lvl, "unknown:" + lvl),\n               "swap_used_mb": float(m.group(1)) if m else None, "swap_total_mb": float(t.group(1)) if t else None,\n               "resident_gb": round(sum(a["rss_mb"] for a in apps.values()) / 1024, 1)},\n    "windowserver": {"cpu_samples": ws["cpu_samples"], "cpu_median": sorted(ws["cpu_samples"])[len(ws["cpu_samples"]) // 2] if ws["cpu_samples"] else None, "rss": ws["rss"]},\n    "apps": [dict(name=k, **r2(v)) for k, v in top[:15]],\n    "chrome": {k: r2(v) for k, v in chrome.items()} or None}))\n'




def sh_in(argv, data, timeout=60):
    try:
        r = subprocess.run(argv, input=data, capture_output=True, text=True, timeout=timeout)
        return r.returncode, r.stdout, r.stderr
    except FileNotFoundError:
        return 127, "", "not found"
    except subprocess.TimeoutExpired:
        return 124, "", "timeout"


def tailnet_macs():
    """Online macOS peers on the tailnet (plus self), with their path: direct or
    relayed through a DERP region. None when tailscale is absent/unanswering."""
    ts = which("tailscale") or ("/Applications/Tailscale.app/Contents/MacOS/Tailscale"
                                if os.path.exists("/Applications/Tailscale.app/Contents/MacOS/Tailscale") else None)
    if not ts:
        return None
    rc, out, _ = sh([ts, "status", "--json"], 15)
    try:
        d = json.loads(out)
    except ValueError:
        return None
    rows = []
    for me, p in [(True, d.get("Self") or {})] + [(False, x) for x in (d.get("Peer") or {}).values()]:
        if p.get("OS") != "macOS":
            continue
        name = (p.get("DNSName") or "").split(".")[0] or norm(p.get("HostName"))
        rows.append({"name": name, "host_name": p.get("HostName"), "self": me, "online": bool(p.get("Online")),
                     "ip": next((i for i in p.get("TailscaleIPs") or [] if "." in i), None),
                     "path": None if me else ("direct " + p["CurAddr"] if p.get("CurAddr") else
                                              f"relayed via DERP {p.get('Relay') or '?'}")})
    return rows


def ensure_host_key(peer):
    """Trust bytes, not a first sighting: the key at the peer's tailnet IP is
    accepted only if it equals a key ssh already trusts for one of its other
    names (<name>.local, its MagicDNS name). Then pinned in hilt's own
    known_hosts. Returns the known_hosts path, or raises Refusal."""
    ip = peer["ip"]
    os.makedirs(os.path.dirname(HILT_KNOWN_HOSTS), exist_ok=True)
    if os.path.exists(HILT_KNOWN_HOSTS):
        rc, out, _ = sh(["ssh-keygen", "-F", ip, "-f", HILT_KNOWN_HOSTS], 5)
        if rc == 0 and out.strip():
            return HILT_KNOWN_HOSTS
    rc, out, _ = sh(["ssh-keyscan", "-T", "8", "-t", "ed25519", ip], 20)
    line = next((l for l in out.splitlines() if l and not l.startswith("#")), None)
    if not line:
        raise Refusal("host-unreachable", f"{peer['name']} ({ip}) did not answer ssh-keyscan.")
    key = line.split()[2]
    aliases = [f"{peer['name']}.local", peer["name"]] + ([peer["host_name"].replace(" ", "-").replace("\u2019", "") + ".local"]
                                                        if peer.get("host_name") else [])
    for a in aliases:
        rc, known, _ = sh(["ssh-keygen", "-F", a], 5)
        if rc == 0 and any(l.split()[-1] == key for l in known.splitlines() if l and not l.startswith("#")):
            with open(HILT_KNOWN_HOSTS, "a") as f:
                f.write(line.strip() + "\n")
            return HILT_KNOWN_HOSTS
    raise Refusal("host-key-unverified", f"the ssh key at {peer['name']} ({ip}) matches no key already "
                  f"trusted for {', '.join(aliases)}. hilt does not trust a first sighting: ssh to it once "
                  "by a name you trust, or add its key to ~/.ssh/known_hosts yourself.")


def ssh_argv(kh, ip, command):
    """hilt's one ssh shape. Measured MBA -> MBP over DERP (2026-09-28): a fresh
    handshake cost 2.6-7.7 s (GSSAPI alone ~1 s) against 0.36-0.68 s on a reused
    connection, so connections persist 10 min in hilt's own state dir. A voice
    question's first remote read pays the handshake; the next ones do not."""
    cp = os.path.join(os.path.dirname(HILT_KNOWN_HOSTS), "ssh-%C")
    return ["ssh", "-o", "BatchMode=yes", "-o", "ConnectTimeout=10", "-o", f"UserKnownHostsFile={kh}",
            "-o", "StrictHostKeyChecking=yes", "-o", "GSSAPIAuthentication=no",
            "-o", "ControlMaster=auto", "-o", f"ControlPath={cp}", "-o", "ControlPersist=600", ip, command]


def fixed_script_read(script, host=None):
    """(parsed JSON, where, err): run a FIXED script with /usr/bin/python3 here, or
    piped over tailnet ssh (host key must match a trusted name). Same transport as thermals."""
    if not host:
        rc, out, err = sh_in(["/usr/bin/python3", "-"], script, 40)
        where = "local"
    else:
        peer = resolve_peer(host)
        if peer["self"]:
            return fixed_script_read(script, None)
        kh = ensure_host_key(peer)
        rc, out, err = sh_in(ssh_argv(kh, peer["ip"], "/usr/bin/python3 -"), script, 60)
        where = f"{peer['name']} via tailscale ({peer['path']})"
    if rc != 0:
        return None, where, (err or out).strip()[:200]
    try:
        return json.loads(out.strip().splitlines()[-1]), where, None
    except (ValueError, IndexError):
        return None, where, out.strip()[:200]


def thermal_read(host=None):
    """(sensors, where) — [(name, °C)] locally, or on a tailnet Mac over ssh."""
    if not host:
        rc, out, err = sh_in(["/usr/bin/python3", "-"], THERMAL_PY, 20)
        where = "local"
    else:
        peer = resolve_peer(host)
        if peer["self"]:
            return thermal_read(None)
        kh = ensure_host_key(peer)
        rc, out, err = sh_in(ssh_argv(kh, peer["ip"], "/usr/bin/python3 -"), THERMAL_PY, 40)
        where = f"{peer['name']} via tailscale ({peer['path']})"
    if rc != 0:
        return None, where, (err or out).strip()[:200]
    try:
        return [tuple(x) for x in json.loads(out.strip().splitlines()[-1])], where, None
    except (ValueError, IndexError):
        return None, where, out.strip()[:200]


def resolve_peer(a):
    peers = tailnet_macs()
    if peers is None:
        raise Refusal("native-unavailable", "tailscale is not installed or not answering: no fleet to reach.")
    hit = [p for p in peers if a.lower() in (p["name"].lower(), (p["ip"] or ""), norm(p["host_name"] or ""))
           or norm(a) == norm(p["name"])]
    if len(hit) != 1:
        raise Refusal("bad-enum", f"'{a}' is not one macOS tailnet peer; one of: "
                      + " | ".join(p["name"] + ("" if p["online"] else " (offline)") for p in peers))
    if not hit[0]["online"]:
        raise Refusal("host-offline", f"{hit[0]['name']} is offline on the tailnet.")
    return hit[0]


# ---------------------------------------------------------------- native: Xcode / dev toolchain
# Mark 2026-09-27: "you offer surface over Xcode so agents don't have to
# re-interrogate it?" The facts every build session re-derives, in ONE read:
# active developer dir, Xcode version/build, SDKs, Swift, simulator runtimes,
# code-signing identities (names + team only — no key material exists here),
# provisioning profiles, Rust. ~1 s in parallel.

def dev_toolchain():
    from concurrent.futures import ThreadPoolExecutor
    cmds = {
        "developer_dir": ["xcode-select", "-p"],
        "xcodebuild": ["xcodebuild", "-version"],
        "sdk_macos": ["xcrun", "--sdk", "macosx", "--show-sdk-version"],
        "sdk_ios": ["xcrun", "--sdk", "iphoneos", "--show-sdk-version"],
        "swift": ["swift", "--version"],
        "runtimes": ["xcrun", "simctl", "list", "runtimes", "-j"],
        "devices": ["xcrun", "simctl", "list", "devices", "available", "-j"],
        "identities": ["security", "find-identity", "-v", "-p", "codesigning"],
        "clt": ["pkgutil", "--pkg-info=com.apple.pkg.CLTools_Executables"],
        "rustc": ["rustc", "--version"], "cargo": ["cargo", "--version"],
    }
    with ThreadPoolExecutor(len(cmds)) as ex:
        res = dict(zip(cmds, ex.map(lambda a: sh(a, 20), cmds.values())))
    ok = lambda k: res[k][0] == 0
    out = {"developer_dir": res["developer_dir"][1].strip() if ok("developer_dir") else None}
    out["using"] = ("xcode" if out["developer_dir"] and ".app/" in out["developer_dir"] else
                    "command-line-tools" if out["developer_dir"] else None)
    m = re.search(r"Xcode (\S+)\s+Build version (\S+)", res["xcodebuild"][1]) if ok("xcodebuild") else None
    out["xcode"] = {"version": m.group(1), "build": m.group(2)} if m else None
    out["sdk"] = {"macos": res["sdk_macos"][1].strip() if ok("sdk_macos") else None,
                  "ios": res["sdk_ios"][1].strip() if ok("sdk_ios") else None}
    m = re.search(r"Apple Swift version (\S+)", res["swift"][1] + res["swift"][2])
    out["swift"] = m.group(1) if m else None
    try:
        rts = json.loads(res["runtimes"][1]).get("runtimes", []) if ok("runtimes") else None
        out["simulator_runtimes"] = None if rts is None else [
            {"name": r.get("name"), "version": r.get("version"), "available": r.get("isAvailable")} for r in rts]
    except ValueError:
        out["simulator_runtimes"] = None
    try:
        devs = json.loads(res["devices"][1]).get("devices", {}) if ok("devices") else None
        out["simulator_devices"] = None if devs is None else sum(len(v) for v in devs.values())
    except ValueError:
        out["simulator_devices"] = None
    ids = []
    for line in res["identities"][1].splitlines() if ok("identities") else []:
        m = re.search(r'\)\s+([0-9A-F]{40})\s+"([^"]+)"', line)
        if m:
            team = re.search(r"\(([A-Z0-9]{10})\)\s*$", m.group(2))
            ids.append({"name": m.group(2), "team": team.group(1) if team else None, "sha1": m.group(1)})
    out["signing_identities"] = ids
    pp = os.path.expanduser("~/Library/MobileDevice/Provisioning Profiles")
    out["provisioning_profiles"] = len(glob.glob(os.path.join(pp, "*.*provisionprofile"))) if os.path.isdir(pp) else 0
    m = re.search(r"^version: (\S+)", res["clt"][1], re.M) if ok("clt") else None
    out["command_line_tools"] = m.group(1) if m else None
    out["rust"] = {"rustc": res["rustc"][1].strip() if ok("rustc") else None,
                   "cargo": res["cargo"][1].strip() if ok("cargo") else None}
    out["python_for_hilt"] = "ok" if out["developer_dir"] else "MISSING: /usr/bin/python3 will prompt to install developer tools"
    return out


def native_records():
    recs = [{"id": "state.audio.devices", "kind": "system.state",
             "outcome": "list audio devices (output/input, transport) and which are the defaults",
             "provider": "native:coreaudio", "authority": "local", "probe": None, "x_params": [],
             "x_native": "audio.devices",
             "x_aliases": ["audio devices", "sound devices", "speakers", "microphones", "headphones",
                           "what audio device", "sound output device"],
             "x_source": ["native:coreaudio"]}]
    for d, words_ in (("output", ["audio output", "sound output", "switch speakers", "switch headphones",
                                  "output device", "play sound through"]),
                      ("input", ["audio input", "microphone input", "switch microphone", "input device",
                                 "use microphone"])):
        recs.append({"id": f"native.audio.{d}", "kind": "system.cli",
                     "outcome": f"set the default audio {d} device",
                     "provider": f"native:coreaudio set default {d} <device>", "authority": "local",
                     "probe": f"coreaudio default {d} device (readback)",
                     "x_params": [{"name": "device", "type": "string", "optional": False, "enum": None,
                                   "dynamic_options": True, "typed_by": f"audio.{d}",
                                   "source": "derived:coreaudio (live device list)"}],
                     "x_native": f"audio.set.{d}", "x_aliases": words_,
                     "x_note": "Native CoreAudio (public API) via ctypes. The device is typed by the "
                               "live device list (`hilt run state.audio.devices`); verified = the "
                               "default reads back as that device.",
                     "x_source": ["native:coreaudio"]})
    recs.append({"id": "state.bluetooth.devices", "kind": "system.state",
                 "outcome": "Bluetooth power and paired devices: connected or not, type, battery",
                 "provider": "system_profiler SPBluetoothDataType", "authority": "local", "probe": None,
                 "x_params": [], "x_native": "bluetooth.devices",
                 "x_aliases": ["bluetooth", "is bluetooth on", "is bluetooth off", "bluetooth devices", "paired devices", "airpods", "earbuds", "buds",
                               "headphones connected", "bluetooth status", "battery of my airpods"],
                 "x_source": ["native:system_profiler"]})
    for sid, (rid, outcome, aliases, extra) in {
        "status.battery": ("state.battery", "battery percent, charging or not, and time remaining",
                           ["battery", "battery level", "how much battery", "am i charging", "is it charging",
                            "time remaining", "power source", "battery percent",
                            "is my mac charging", "mac charging", "is it plugged in",
                            "how much battery do i have", "battery left", "how much battery is left"], {}),
        "status.uptime": ("state.uptime", "how long since this Mac booted",
                          ["uptime", "how long has it been on", "when did it boot", "last restart", "last reboot"], {}),
        "status.disk": ("state.disk", "free and total space on the data volume",
                        ["disk space", "free space", "storage", "how much space", "disk free", "is my disk full",
                         "how much disk space is left", "how much storage is left", "space left"], {}),
        "status.wifi": ("state.wifi.current", "current Wi-Fi: connected or not, signal strength (dBm, SNR), band, rate",
                        ["wifi signal", "wifi strength", "am i on wifi", "which wifi", "current network",
                         "signal strength", "wifi status", "connected to wifi",
                         "my wifi signal", "how good is my wifi", "wifi network",
                         "what's my wifi network", "what wifi am i connected to", "which wifi network", "wifi name"], {}),
        "status.audio": ("state.audio.now", "what sound plays through now, at what volume (muted or not), and the input",
                         ["volume", "how loud", "is it muted", "current volume", "what speaker",
                          "where is sound going", "sound output now", "loud",
                          "how loud is it", "what is the volume", "volume level"], {}),
        "status.bluetooth": ("state.bluetooth.connected", "which Bluetooth devices are connected now, with battery",
                             ["connected bluetooth", "what is connected", "are my airpods connected",
                              "bluetooth connected", "headphones battery"], {}),
        "status.focus": ("state.focus", "Focus / Do Not Disturb: on or off, which mode, and its schedule",
                         ["focus", "do not disturb", "dnd", "is do not disturb on", "focus mode", "notifications silenced"],
                         {"x_private_api": "~/Library/DoNotDisturb/DB (Focus daemon files, read-only)",
                          "x_tcc": "kTCCServiceSystemPolicyAllFiles"}),
        "status.brightness": ("state.display.brightness", "built-in screen brightness",
                              ["brightness", "screen brightness", "how bright", "display brightness",
                               "how bright is the screen", "bright screen"],
                              {"x_private_api": "DisplayServicesGetBrightness"}),
    }.items():
        recs.append({"id": rid, "kind": "system.state", "outcome": outcome,
                     "provider": f"native:{sid} (read-only) [host via tailscale ssh]",
                     "authority": "local", "probe": None, "x_params": [dict(HOST_PARAM)], "x_native": sid,
                     "x_aliases": aliases,
                     "x_note": "Read-only status read: `after.speak` is one sentence to say as is; `after.units` "
                               "names the unit of every numeric value. With a host, the same reader runs on that "
                               "tailnet Mac (hilt's own bytes over trusted-key ssh).", "x_source": ["native"], **extra})
    recs.append({"id": "native.focus.set", "kind": "system.cli",
                 "outcome": "turn Do Not Disturb on or off",
                 "provider": "shortcuts run \"Do Not Disturb On|Off\" (a user Shortcut with Set Focus)",
                 "authority": "local", "probe": "state.focus (readback)",
                 "x_params": [{"name": "state", "type": "string", "optional": False, "enum": ["on", "off"],
                               "source": "authored"}],
                 "x_native": "focus.set",
                 "x_aliases": ["do not disturb", "dnd", "activate do not disturb", "set do not disturb", "turn on do not disturb", "turn off do not disturb",
                               "do not disturb on", "do not disturb off", "enable do not disturb",
                               "disable do not disturb", "silence notifications", "dnd on", "dnd off",
                               "turn on focus", "turn off focus", "set focus"],
                 "x_note": "No public CLI sets Focus. hilt runs two Shortcuts a human makes once "
                           "(" + FOCUS_SHORTCUTS["on"] + " / " + FOCUS_SHORTCUTS["off"] + "); without them it "
                           "REFUSES with the steps. Verified = state.focus reads the requested state.",
                 "x_undo": "hilt run native.focus.set off", "x_source": ["shortcuts"]})
    onoff = lambda name: [{"name": name, "type": "string", "optional": False, "enum": ["on", "off"], "source": "authored"}]
    recs += [
        {"id": "native.audio.volume", "kind": "system.cli", "outcome": "set the output volume (0-100, or up / down a step)",
         "provider": "native:audiotoolbox virtual main volume", "authority": "local", "probe": "volume readback",
         "x_params": [{"name": "level", "type": "string", "optional": False, "enum": None, "typed_by": "audio.level",
                       "source": "0..100 | up | down"}], "x_native": "audio.volume",
         "x_aliases": ["volume", "set volume", "set the volume", "turn up the volume", "turn down the volume",
                       "volume up", "volume down", "louder", "quieter", "make it louder", "make it quieter"],
         "x_undo": "run it again with before.volume_percent", "x_source": ["native:coreaudio"]},
        {"id": "native.audio.mute", "kind": "system.cli", "outcome": "mute or unmute the sound output",
         "provider": "native:coreaudio mute", "authority": "local", "probe": "mute readback", "x_params": onoff("state"),
         "x_native": "audio.mute", "x_say": {"mute": "on", "unmute": "off"},
         "x_aliases": ["mute", "unmute", "mute the sound", "mute sound", "mute audio", "unmute the sound", "silence"],
         "x_undo": "hilt run native.audio.mute off", "x_source": ["native:coreaudio"]},
        {"id": "native.wifi.power", "kind": "system.cli", "outcome": "turn Wi-Fi on or off",
         "provider": "networksetup -setairportpower <wifi device> on|off", "authority": "local",
         "probe": "networksetup -getairportpower", "x_params": onoff("state"), "x_native": "wifi.power",
         "x_aliases": ["turn off wifi", "turn on wifi", "wifi off", "wifi on", "disable wifi", "enable wifi",
                       "wifi power", "turn wifi off", "turn wifi on"],
         "x_undo": "hilt run native.wifi.power on",
         "x_note": "Turning Wi-Fi off also drops Tailscale over Wi-Fi: a remote caller loses this Mac.",
         "x_source": ["networksetup"]},
        {"id": "native.appearance.dark", "kind": "system.cli", "outcome": "turn dark mode on or off (light appearance)",
         "provider": "System Events appearance preferences (live)", "authority": "local",
         "probe": "defaults read -g AppleInterfaceStyle", "x_params": onoff("state"), "x_native": "appearance.dark",
         "x_aliases": ["dark mode", "turn on dark mode", "turn off dark mode", "dark mode on", "dark mode off",
                       "light mode", "enable dark mode", "disable dark mode"],
         "x_undo": "hilt run native.appearance.dark off", "x_tcc": None, "x_source": ["system events"]},
        {"id": "native.screen.lock", "kind": "system.cli", "outcome": "lock the screen now",
         "provider": "System Events keystroke ⌃⌘Q (Apple's lock shortcut)", "authority": "local",
         "probe": "CGSessionCopyCurrentDictionary CGSSessionScreenIsLocked", "x_params": [], "x_native": "screen.lock",
         "x_aliases": ["lock the screen", "lock screen", "lock my mac", "lock the mac", "lock computer"],
         "x_undo": "a person unlocks it", "x_source": ["system events"]},
    ]
    bridge_note = ("Through the one-time \"hilt\" Shortcut (`hilt setup shortcuts`; it refuses setup-required with that "
                   "fix until imported). Verified by an independent readback.")
    for what, rid, label_words, aliases, probe in (
            ("bluetooth", "native.bluetooth.power", "Bluetooth",
             ["turn on bluetooth", "turn off bluetooth", "bluetooth on", "bluetooth off", "enable bluetooth",
              "disable bluetooth", "bluetooth power"], "system_profiler SPBluetoothDataType controller state"),
            ("nightshift", "native.nightshift", "Night Shift",
             ["night shift", "turn on night shift", "turn off night shift", "night shift on", "night shift off",
              "warm screen", "blue light"], "CoreBrightness CBBlueLightClient status (private, read-only)"),
            ("lowpower", "native.lowpower", "Low Power Mode",
             ["low power mode", "turn on low power mode", "turn off low power mode", "low power", "battery saver",
              "save battery"], "pmset -g lowpowermode")):
        recs.append({"id": rid, "kind": "system.cli", "outcome": f"turn {label_words} on or off",
                     "provider": ("sudo pmset -a lowpowermode 1|0 (a human: needs admin)" if what == "lowpower"
                                  else f"shortcut: hilt ({what} on|off)"), "authority": "local", "probe": probe,
                     "x_params": onoff("state"), "x_native": f"bridge.{what}", "x_aliases": aliases,
                     "x_note": bridge_note, "x_undo": "run it again with the other state", "x_source": ["shortcuts"]})
    recs.append({"id": "state.nightshift", "kind": "system.state", "outcome": "Night Shift: on or off now",
                 "provider": "CoreBrightness CBBlueLightClient status (private, read-only)", "authority": "local",
                 "probe": None, "x_params": [], "x_native": "nightshift.read", "x_private_api": "CBBlueLightClient",
                 "x_aliases": ["is night shift on", "is night shift off", "night shift status", "night shift"],
                 "x_source": ["native:corebrightness"]})
    recs.append({"id": "native.display.brightness", "kind": "system.cli",
                 "outcome": "set the built-in screen brightness (0-100 in steps of 10, or up / down)",
                 "provider": "shortcut: hilt (brightness N)", "authority": "local",
                 "probe": "DisplayServicesGetBrightness (private, read-only)",
                 "x_params": [{"name": "level", "type": "string", "optional": False, "enum": None,
                               "typed_by": "display.level", "source": "0..100 | up | down"}],
                 "x_native": "bridge.brightness",
                 "x_aliases": ["brightness", "screen brightness", "set brightness", "set the brightness", "make the screen brighter",
                               "make the screen dimmer", "brighter", "dimmer", "brightness up", "brightness down",
                               "dim the screen", "brighten the screen", "turn up the brightness",
                               "turn down the brightness"],
                 "x_note": bridge_note, "x_undo": "run it again with before.brightness_percent",
                 "x_source": ["shortcuts"]})
    # Find My has no App Intents, no sdef, and its cache is encrypted (since macOS
    # 14.4), so hilt cannot READ it. It can open the right view for a human:
    # findmy://devices landed on the Devices list (Mark, 2026-09-24).
    recs.append({"id": "state.thermal.sensors", "kind": "system.state",
                 "outcome": "temperature sensors (SoC die, power, storage) here or on a tailnet Mac; coolest = room upper bound",
                 "provider": "native:iohid temperature sensors (private, read-only) [host via tailscale ssh]",
                 "authority": "local", "probe": None,
                 "x_params": [dict(HOST_PARAM)],
                 "x_native": "thermal.sensors", "x_private_api": "IOHIDEventSystemClient",
                 "x_aliases": ["temperature", "temps", "cpu temperature", "how hot", "thermal", "ambient temperature",
                               "room temperature", "sensors", "why is my mac warm", "why is my mac hot", "mac warm",
                               "mac hot", "warm", "overheating", "running hot", "is my mac overheating"],
                 "x_note": "PRIVATE IOKit HID API, read-only (approved by Mark 2026-09-26). No ambient-air sensor "
                           "exists on these Macs: an idle machine only adds heat, so the coolest sensor is an UPPER "
                           "BOUND on the room. Remote: the same fixed script piped over ssh; the host key must match "
                           "one already trusted for that Mac.",
                 "x_source": ["native:iohid", "tailscale"]})
    recs.append({"id": "state.resources", "kind": "system.state",
                 "outcome": "what is using this Mac now: memory and CPU by app (helpers grouped), WindowServer sampled, memory pressure and swap",
                 "provider": "ps + top (sampled) + sysctl, a fixed read-only script [host via tailscale ssh]",
                 "authority": "local", "probe": None,
                 "x_params": [dict(HOST_PARAM)],
                 "x_native": "resources",
                 "x_aliases": ["memory", "ram", "what is using memory", "why is my mac slow", "cpu usage",
                               "chrome memory", "windowserver", "memory pressure", "swap", "activity",
                               "which app is hogging the cpu", "what is hogging the cpu",
                               "which app is using the most cpu", "using the most cpu", "most cpu", "top cpu", "hogging cpu", "cpu hog",
                               "hogging", "how much memory is free", "how much memory is free right now", "free memory",
                               "memory free", "is anything using a lot of memory", "lot of memory", "using a lot",
                               "summarize how this mac is doing", "how is this mac doing", "how is my mac doing",
                               "system health", "mac health", "summarize"],
                 "x_note": "Read-only, ~3 s (WindowServer is sampled). Facts + macOS's own pressure level; hilt sets "
                           "no thresholds — Zil alerts. Evidence, not blame: prove a culprit by quitting it and re-reading.",
                 "x_source": ["native:ps", "native:top", "native:sysctl"]})
    recs.append({"id": "state.fleet.macs", "kind": "system.state",
                 "outcome": "the Macs on the tailnet: online, IP, and whether the path is direct or DERP-relayed",
                 "provider": "tailscale status --json", "authority": "local", "probe": None, "x_params": [],
                 "x_native": "fleet.macs",
                 "x_aliases": ["fleet", "my macs", "tailnet", "tailscale peers", "which macs are online"],
                 "x_source": ["tailscale"]})
    recs.append({"id": "state.dev.xcode", "kind": "system.state",
                 "outcome": "Xcode / dev toolchain: active developer dir, Xcode + SDK + Swift versions, simulators, signing identities, Rust",
                 "provider": "xcode-select, xcodebuild, xcrun, simctl, security find-identity (read-only, parallel)",
                 "authority": "local", "probe": None, "x_params": [], "x_native": "dev.xcode",
                 "x_aliases": ["xcode", "xcode version", "which sdk", "sdk version", "simulators", "ios simulator",
                               "signing identity", "developer id", "code signing", "swift version", "toolchain",
                               "team id", "rust version"],
                 "x_note": "Read-only, ~1 s. Identities are names + team + SHA-1 fingerprint (no key material). "
                           "No simulator runtime installed = iOS simulator builds fail here: check before trying.",
                 "x_source": ["native:xcode"]})
    recs.append({"id": "state.quarantine.agents", "kind": "system.state",
                 "outcome": "which agent binaries carry the quarantine mark (Gatekeeper 'open?' prompt when a desk app launches them)",
                 "provider": "xattr -p com.apple.quarantine <resolved binary>", "authority": "local", "probe": None,
                 "x_params": [], "x_native": "quarantine.agents",
                 "x_aliases": ["quarantine", "gatekeeper prompt", "open prompt", "codex asks to open",
                               "downloaded from the internet"],
                 "x_note": "Read-only. The list is setup-profiles.json quarantine_check.dev. Removing the mark "
                           "is the human's call: each quarantined row carries its human_command.",
                 "x_source": ["native:xattr"]})
    recs.append({"id": "system.findmy.devices", "kind": "system.pane",
                 "outcome": "open Find My › Devices (where your Apple devices and AirPods are)",
                 "provider": "open:findmy://devices", "authority": "human-required", "probe": None,
                 "x_aliases": ["find my", "find my devices", "where are my airpods", "find my airpods",
                               "locate my devices", "where is my"],
                 "x_note": "Opens Find My on the Devices list; a human reads it. Find My shows what is "
                           "registered to the Apple ID, not what is paired over Bluetooth: AirPods paired "
                           "only to this Mac may be absent (seen 2026-09-24). For proximity from this Mac, "
                           "state.bluetooth.mine-nearby. Deep-link witnessed by Mark 2026-09-24.",
                 "x_source": ["authored:url-scheme"]})
    recs.append({"id": "state.bluetooth.mine-nearby", "kind": "system.state",
                 "outcome": "are my AirPods (or other paired devices) nearby — even when not connected",
                 "provider": "system_profiler SPBluetoothDataType (live LE links)", "authority": "local",
                 "probe": None, "x_params": [], "x_native": "bluetooth.mine-nearby",
                 "x_aliases": ["are my airpods nearby", "where are my airpods", "airpods nearby",
                               "airpods in range", "my devices nearby"],
                 "x_note": "No scan, no permission. NEARBY when a live link exists: classic connected, or "
                           "the LE twin macOS keeps to YOUR AirPods (walk-away witnessed 2026-09-24: it "
                           "tracked RSSI and dropped out of range). No link = UNKNOWN, never 'not nearby': "
                           "the twin did not re-form on return. Galaxy Buds never have a twin.",
                 "x_source": ["native:system_profiler"]})
    recs.append({"id": "state.wifi.scan", "kind": "system.state",
                 "outcome": "Wi-Fi networks in range: name, signal, channel, band, open or secured (~8 s)",
                 "provider": "native:corewlan scan", "authority": "local", "probe": None, "x_params": [],
                 "x_native": "wifi.scan",
                 "x_aliases": ["wifi networks", "wifi scan", "what networks are around", "available wifi", "nearby wifi",
                               "which wifi networks", "scan for wifi", "hotel wifi"],
                 "x_note": "CoreWLAN scan through the fixed JXA door. SSIDs of OTHER networks come back without "
                           "Location; the one you are on stays hidden without it. ~7.7 s measured.",
                 "x_source": ["native:corewlan"]})
    recs.append({"id": "native.wifi.join", "kind": "system.cli",
                 "outcome": "join an OPEN Wi-Fi network by name (from the scan); a secured one refuses with the line a human types the password into",
                 "provider": "native:corewlan associate <ssid>", "authority": "local", "probe": "channel of the joined network",
                 "x_params": [{"name": "ssid", "type": "string", "optional": False, "enum": None, "typed_by": "wifi.scanned",
                               "source": "live:corewlan scan"}],
                 "x_native": "wifi.join",
                 "x_aliases": ["join wifi", "connect to wifi", "join the network", "connect to the hotel wifi", "switch wifi network"],
                 "x_note": "Measured 2026-10-04: associate with no password on a known SECURED network disassociates "
                           "and fails -3900 (the saved credential is not used), so hilt only joins open networks; "
                           "for a secured one the refusal carries `networksetup -setairportnetwork <dev> \"<ssid>\" <password>` "
                           "for a human. Verified by the channel the Mac is on afterwards (the SSID is hidden by Location).",
                 "x_source": ["native:corewlan"]})
    recs.append({"id": "state.bluetooth.nearby", "kind": "system.state",
                 "outcome": "scan for Bluetooth devices in range that are discoverable (pairing mode), with signal strength",
                 "provider": "native:iobluetooth device inquiry <seconds>", "authority": "local", "probe": None,
                 "x_params": [{"name": "seconds", "type": "integer", "optional": True, "enum": None,
                               "range": [4, 20], "source": "authored"}],
                 "x_native": "bluetooth.nearby", "x_tcc": "kTCCServiceBluetoothAlways",
                 "x_aliases": ["bluetooth devices in range", "nearby bluetooth", "available bluetooth devices",
                               "bluetooth scan", "what bluetooth devices are available", "discoverable devices"],
                 "x_note": "A timed classic-Bluetooth inquiry (default 8 s, ~12 s wall). Sees ONLY devices "
                           "in discoverable/pairing mode; paired devices idle nearby are invisible to it. "
                           "Also lists what is connected now. Preflighted like connect.",
                 "x_source": ["native:iobluetooth"]})
    for act, words_ in (("connect", ["connect airpods", "connect headphones", "connect buds",
                                     "connect bluetooth", "pair", "use my airpods"]),
                        ("disconnect", ["disconnect airpods", "disconnect headphones", "disconnect buds",
                                        "disconnect bluetooth"])):
        recs.append({"id": f"native.bluetooth.{act}", "kind": "system.cli",
                     "outcome": f"{act} a paired Bluetooth device (AirPods, buds, keyboard…)",
                     "provider": f"native:iobluetooth {act} <device>", "authority": "local",
                     "probe": "system_profiler SPBluetoothDataType connected state",
                     "x_params": [{"name": "device", "type": "string", "optional": False, "enum": None,
                                   "dynamic_options": True, "typed_by": "bluetooth.paired",
                                   "source": "derived:system_profiler (paired list at call time)"}],
                     "x_native": f"bluetooth.{act}", "x_tcc": "kTCCServiceBluetoothAlways",
                     "x_aliases": words_,
                     "x_note": "IOBluetooth (public) via one fixed JXA script, device address as argv. "
                               "Preflighted: refused if the responsible app is denied Bluetooth, or "
                               "has never been asked (it would prompt and an unattended caller would "
                               "hang) unless --allow-prompt. Verified = system_profiler reads the new "
                               "state within 12 s.",
                     "x_source": ["native:iobluetooth"]})
    return recs


def scan_shortcuts():
    rc, out, _ = sh(["shortcuts", "list", "--show-identifiers"], 30)
    recs = []
    for line in out.splitlines():
        m = re.match(r"^(.*) \(([0-9A-F-]{36})\)$", line.strip())
        if not m:
            continue
        name, uid = m.groups()
        if name in FOCUS_SHORTCUTS.values() or name == BRIDGE_NAME:
            continue  # native.focus.set runs these; one surface, not two
        recs.append({"id": f"shortcut.{uid.lower()}", "kind": "shortcut.run",
                     "outcome": f"run shortcut: {name}", "provider": f"shortcuts run {uid}",
                     "authority": "local", "probe": None, "x_aliases": [name.lower()],
                     "x_argv": ["shortcuts", "run", uid],
                     "x_note": "User-authored; its effect is opaque to hilt, so run is "
                               "unverifiable unless a probe is authored.",
                     "x_source": ["shortcuts"]})
    return recs, {"count": len(recs), "denominator": len(recs) if rc == 0 else None,
                  "unit": "user shortcuts", "status": "ok" if rc == 0 else "shortcuts CLI failed"}


def scan_domains(bids, spotlight):
    rc, out, _ = sh(["defaults", "domains"], 30)
    names = [d.strip() for d in out.split(",") if d.strip()] if rc == 0 else []
    doms = {}
    for d in names:
        f = os.path.join(PREFS_USER, d + ".plist")
        doms[d] = {"plist": f if os.path.exists(f) else None,
                   "bundles": bids.get(d, []) if spotlight == "enabled" else None}
    with_plist = sum(1 for v in doms.values() if v["plist"])
    owned = sum(1 for v in doms.values() if v["bundles"])
    return doms, {"count": len(doms), "denominator": len(doms), "unit": "user defaults domains",
                  "with_plist": with_plist, "owner_resolved": owned if spotlight == "enabled" else None}


def source_root():
    """Where the AUTHORED sources (probes/, traps/) live. An installed copy in
    ~/.local/bin has none beside it, and reading "none" as "zero settings" once
    shipped an index with 0/0 settings and no traps. So: HILT_ROOT, else beside
    this file's realpath, else the root the current index was built from.
    None means build refuses — never a silent zero."""
    cands = [(os.environ.get("HILT_ROOT"), "HILT_ROOT"),
             (os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "beside hilt")]
    try:
        cands.append((json.load(open(INDEX)).get("source_root"), "recorded in the current index"))
    except Exception:
        pass
    for root, how in cands:
        if root and os.path.isfile(os.path.join(root, "probes", "settings.json")):
            return root, how
    return None, None


def load_settings(domains):
    """Authored settings: a key someone named with an outcome. Validated
    against the DERIVED domain list and the live key type before it enters
    the index — an authored row that fails is reported, never installed."""
    rows = json.load(open(SETTINGS_SRC)).get("settings", [])
    recs, rejected = [], []
    for r in rows:
        dom, key, typ = r["domain"], r["key"], r["type"]
        if typ not in PARAM_TYPES:
            rejected.append({"id": r["id"], "why": f"type {typ!r} is not one of the closed list "
                                                 f"{'|'.join(PARAM_TYPES)}"})
            continue
        pathspec = None
        if typ == "path":
            pathspec, why = path_spec(r.get("path") or {})
            if why:
                rejected.append({"id": r["id"], "why": why})
                continue
        if dom not in domains and dom not in GLOBAL_DOMAINS:
            rejected.append({"id": r["id"], "why": f"domain {dom} not on this box"})
            continue
        live = None
        f = (os.path.join(PREFS_USER, ".GlobalPreferences.plist") if dom in GLOBAL_DOMAINS
             else (domains.get(dom) or {}).get("plist"))
        pl = read_plist(f) if f else None
        if isinstance(pl, dict) and key in pl:
            live = ptype(pl[key])
            ok = live == PLIST_TYPE.get(typ, typ) or (typ == "float" and live == "integer") or (typ == "integer" and live == "float")
            if not ok:
                rejected.append({"id": r["id"], "why": f"declared {typ}, live value is {live}"})
                continue
        dflag = "-g" if dom in GLOBAL_DOMAINS else dom
        recs.append({
            "id": r["id"], "kind": "system.setting", "outcome": r["outcome"],
            "provider": f"defaults write {dflag} {key} {WRITE_FLAG[typ]} <value>",
            "authority": "local",
            "probe": f"defaults read {dflag} {key}",
            "x_params": [{"name": "value", "type": typ, "optional": False,
                          "enum": r.get("enum") or (["true", "false"] if typ == "boolean" else None),
                          "range": r.get("range"), **(pathspec or {})}],
            "x_domain": dom, "x_key": key,
            "x_live_type": live, "x_live_present": live is not None,
            "x_reload": r.get("reload"), "x_effect": r.get("effect", "on reload"),
            "x_live_sysevents": r.get("live"),
            "x_say": r.get("say"),
            "x_aliases": [a.lower() for a in r.get("aliases", [])],
            "x_intent_hint": r.get("intent"),
            "x_label_authored": r.get("label"),
            "x_source": ["settings:authored", "defaults"],
        })
    return recs, {"count": len(recs), "denominator": len(rows), "unit": "authored settings validated",
                  "rejected": rejected}


# The param types an authored setting may declare. A CLOSED list: a type not
# here rejects the row at build, and run refuses any param it cannot check.
PARAM_TYPES = ("boolean", "integer", "float", "string", "path")
PLIST_TYPE = {"path": "string"}  # defaults stores a path as a string
PATH_RULES = ("exist", "directory", "writable", "parent-writable")


def path_spec(spec):
    """An authored path param: which rules it must pass, and the roots it must
    resolve under (home by default, widened per row). Validated at build."""
    must = spec.get("must", list(PATH_RULES))
    bad = [m for m in must if m not in PATH_RULES]
    if bad:
        return None, f"path rule(s) {bad} not in the closed list {'|'.join(PATH_RULES)}"
    roots = spec.get("roots", ["~"])
    if not roots or not all(isinstance(x, str) and (x.startswith("/") or x == "~" or x.startswith("~/"))
                            for x in roots):
        return None, f"path roots {roots!r} must be absolute or under ~"
    return {"must": list(must), "roots": list(roots)}, None


def resolve_path(v):
    return os.path.realpath(os.path.expanduser(v))


def check_path(p, a):
    """Refuse a path argument by the FIRST rule it fails, named in `why`.
    Symlinks resolve before the containment test, so a link under ~ that
    points at /tmp is outside ~. Returns the resolved path: that is what gets
    written, so the value checked is the value stored (no re-resolution later)."""
    if not a or "\0" in a or "\n" in a:
        raise Refusal("path-not-absolute", f"'{a}' is not a usable path for '{p['name']}'.")
    raw = os.path.expanduser(a)
    if not os.path.isabs(raw):
        raise Refusal("path-not-absolute", f"'{a}' is not absolute (nor under ~) for '{p['name']}'.")
    rp = os.path.realpath(raw)
    roots = [resolve_path(x) for x in p.get("roots") or ["~"]]
    if not any(rp == r or rp.startswith(r.rstrip("/") + "/") for r in roots):
        raise Refusal("path-outside-root", f"'{a}' resolves to {rp}, which is not under "
                      f"{' or '.join(roots)} (the allowed root(s) for '{p['name']}').", resolved=rp)
    must = p.get("must") or []
    if "exist" in must and not os.path.exists(rp):
        raise Refusal("path-must-exist", f"{rp} does not exist.", resolved=rp)
    if "directory" in must and not os.path.isdir(rp):
        raise Refusal("path-must-be-directory", f"{rp} is not a directory.", resolved=rp)
    if "writable" in must and not os.access(rp, os.W_OK):
        raise Refusal("path-must-be-writable", f"{rp} is not writable by this user.", resolved=rp)
    if "parent-writable" in must and not (os.path.isdir(os.path.dirname(rp)) and os.access(os.path.dirname(rp), os.W_OK)):
        raise Refusal("path-parent-must-be-writable", f"{os.path.dirname(rp)} is not a writable directory.", resolved=rp)
    return rp


PRIVACY_PANE = "com.apple.settings.PrivacySecurity.extension"


def load_tcc_map(root, panes):
    """probes/tcc.json: TCC service -> name + Privacy anchor. Each anchor must
    exist among the DERIVED anchors of the Privacy & Security pane, or the row
    is rejected (a hole in orient) — an authored link never outranks the pane's
    own search index."""
    src = os.environ.get("HILT_TCC") or (root and os.path.join(root, "probes", "tcc.json"))
    try:
        rows = json.load(open(src)).get("services", {})
    except (OSError, TypeError, ValueError):
        return {}, {"count": 0, "denominator": None, "unit": "TCC services mapped to a Privacy anchor",
                    "status": f"no tcc map at {src}", "rejected": []}
    by_anchor = {r["x_anchor"]: r["id"] for r in panes
                 if r.get("x_bundle") == PRIVACY_PANE and r.get("x_anchor")}
    out, rejected = {}, []
    for svc, v in rows.items():
        a = v.get("anchor")
        if a is not None and a not in by_anchor:
            rejected.append({"id": svc, "why": f"anchor {a} is not in the Privacy pane's search index here"})
            continue
        out[svc] = {"name": v.get("name") or svc, "anchor": a, "pane": by_anchor.get(a),
                    "tier": v.get("tier", "other"), "breaks": v.get("breaks"), "pppc": v.get("pppc", "unknown"),
                    "pppc_verified": bool(v.get("pppc_verified"))}
    return out, {"count": len(out), "denominator": len(rows),
                 "unit": "TCC services mapped (anchor validated or declared absent)", "rejected": rejected}


def load_requirements(root):
    """probes/requirements.json, validated: a closed provider/level list, and —
    when brew is on PATH — every formula must be one brew knows (one batched
    `brew info`). A row that fails is rejected into orient's holes."""
    src = os.environ.get("HILT_REQUIREMENTS") or (root and os.path.join(root, "probes", "requirements.json"))
    try:
        rows = json.load(open(src)).get("requirements", [])
    except (OSError, TypeError, ValueError):
        return [], {"count": 0, "denominator": None, "unit": "requirements validated",
                    "status": f"no requirements at {src}", "rejected": []}
    ok, rejected = [], []
    formulas = sorted({r["formula"] for r in rows if r.get("provider") == "brew" and r.get("formula")})
    known, brew = None, which("brew")
    if brew and formulas:
        rc, out, _ = sh([brew, "info", "--json=v2", *formulas], 60)
        try:
            d = json.loads(out) if out.strip() else {}
            known = {x.get("name") for x in d.get("formulae", [])} | {x.get("token") for x in d.get("casks", [])}
        except ValueError:
            known = None  # brew answered garbage: cannot check, do not reject
    for r in rows:
        why = None
        if r.get("provider") not in ("brew", "fleet"):
            why = f"provider {r.get('provider')!r} is not brew|fleet"
        elif r.get("level") not in ("recommended", "optional"):
            why = f"level {r.get('level')!r} is not recommended|optional"
        elif not r.get("binary") or not re.fullmatch(r"[A-Za-z0-9._-]+", r["binary"]):
            why = "binary must be a bare command name"
        elif r["provider"] == "brew" and known is not None and r.get("formula") not in known:
            why = f"brew does not know formula {r.get('formula')!r}"
        elif any(not re.fullmatch(r"[a-z][a-z0-9-]*", sub) or not all(re.fullmatch(r"--[a-z][a-z0-9-]*", f) for f in fl)
                 for sub, fl in (r.get("needs") or {}).items()):
            why = "needs must map a bare subcommand to --flags"
        (rejected.append({"id": r.get("id"), "why": why}) if why else ok.append(r))
    return ok, {"count": len(ok), "denominator": len(rows), "unit": "requirements validated",
                "formulas_checked": known is not None, "rejected": rejected}


def load_traps():
    return json.load(open(TRAPS_SRC)).get("traps", [])


RUNNABLE_KINDS = ("system.setting", "application.launch", "system.state", "system.cli", "shortcut.run")


def runnable(r):
    return r["authority"] == "local" and r["kind"] in RUNNABLE_KINDS and (
        r["kind"] in ("system.setting", "application.launch") or r.get("x_argv") or r.get("x_witness")
        or r.get("x_verb") or r.get("x_native"))


def proven_runs(build_id):
    """Authority confidence is DERIVED, not authored: an id is `measured` when
    runs.jsonl holds a `verified` or `query` run of it on THIS OS build. An OS
    update resets every record to `unverified` until something runs it again.
    Read-only; a missing or torn log proves nothing."""
    out = {}
    try:
        for line in open(RUNS):
            try:
                r = json.loads(line)
            except ValueError:
                continue
            if r.get("verdict") in ("verified", "query") and r.get("os_build") == build_id and r.get("id"):
                out[r["id"]] = max(out.get(r["id"], 0), r.get("ts") or 0)
    except OSError:
        pass
    return out


def fda_status():
    """Full Disk Access of THIS process's host, by the one test that is the definition: can
    it read the user TCC database. granted | not-granted (the file is there, EPERM) |
    hidden (the path does not resolve: a sandboxed shell, which hides the directory —
    measured 2026-10-04 from Claude Code's Bash; not a verdict about the host app).
    Live at orient time, never from the index: a build made in a sandbox must not
    stamp the host's grant."""
    tcc = user_tcc_db()
    try:
        with open(tcc, "rb") as f:
            f.read(16)
        return "granted"
    except PermissionError:
        pass
    except FileNotFoundError:
        pass
    except OSError:
        pass
    # macOS 27 seals the database even for FDA holders (§36): the witness is a file only
    # Full Disk Access can read (Safari bookmarks, Mail, Messages)
    w = tcc_probe(FDA_SERVICE) if os.environ.get("HILT_TCC_PROBE", "1") != "0" else None
    return "granted" if w == "allowed" else ("not-granted" if w == "not-granted" else "hidden")


# ---- RECALL (spec §38, Mark 2026-10-10): when word matching returns nothing, rank records
# by meaning. Vectors come from an ollama-compatible /api/embed endpoint — local by default,
# a tailnet host when HILT_EMBED_URL names one — computed at `hilt build`, cached by model +
# text hash, stored beside the index (an embedding app's HILT_INDEX gets its own). Recall
# never makes a result unique: a similarity is a guess, so it feeds a chooser (rift) or a
# human, never an auto-run. Endpoint down → word-only, and the answer says why.
EMBED_URL = (os.environ.get("HILT_EMBED_URL") or "http://127.0.0.1:11434").rstrip("/")
EMBED_MODEL = os.environ.get("HILT_EMBED_MODEL") or "embeddinggemma"  # measured best of 3, spec §38
RECALL_ON = os.environ.get("HILT_RECALL", "1") != "0"
RECALL_CACHE_DIR = os.environ.get("HILT_RECALL_CACHE") or os.path.join(STATE, "hilt", "recall-cache")
# Cosine floors PER MODEL (their scales differ: nomic's off-topic phrases score 0.45-0.58 where
# EmbeddingGemma's score 0.14-0.35), each the floor that keeps >=90% of the off-topic set NONE
# while maximizing paraphrase top-5 (tools/eval-recall.py --sweep, 2026-10-10). An untuned
# model gets 0.30 and says so in coverage.
RECALL_FLOORS = {"embeddinggemma": 0.34, "all-minilm": 0.30, "nomic-embed-text": 0.58}
RECALL_MIN = float(os.environ.get("HILT_RECALL_MIN") or RECALL_FLOORS.get(EMBED_MODEL.split(":")[0], 0.30))
RECALL_TOP = 8
# The TEXT RECIPE is versioned apart from the model (borrowed from daystra's librarian,
# #hilt 375: changing how the text is built invalidates vectors just as a model change does).
RECALL_TEXT_VERSION = "v2"
# ollama 0.40.3 (auto-updated 2026-10-11) resets its runner on a 256-text batch of record texts;
# 128 embeds 256 texts in ~3.6 s. Measured, not guessed: a cold-cache build failed at 256.
RECALL_BATCH = 128
# Models trained with task prefixes score far better with them (their model cards); a model
# without an entry gets bare text. (query prefix, document prefix)
EMBED_PREFIX = {"nomic-embed-text": ("search_query: ", "search_document: "),
                "embeddinggemma": ("task: search result | query: ", "title: none | text: ")}


def embed_prefix(model=None):
    return EMBED_PREFIX.get((model or EMBED_MODEL).split(":")[0], ("", ""))


class RecallError(Exception):
    pass


def recall_corpus(records):
    """Records recall may surface: not describe-only intents, not app verbs `run` refuses."""
    return [r for r in records if r["kind"] != "system.intent"
            and not (r["kind"] == "application.verb" and r["id"].split(".do.")[-1] not in SAFE_VERBS)]


def recall_text(r):
    # v2 (2026-10-11): EVERY alias, not the first 12 — top-1 29→32, top-5 60→62 of 96 with no new
    # off-topic leak (spec §38). No kind gloss: one shared sentence across 549 panes compresses margins.
    return " · ".join(x for x in (r.get("x_label") or "", r["outcome"], ", ".join(r.get("x_aliases") or []),
                                  r.get("x_situation") or "") if x)


def embed(texts, url=None, model=None, timeout=10):
    import urllib.request, urllib.error
    req = urllib.request.Request((url or EMBED_URL) + "/api/embed", headers={"Content-Type": "application/json"},
                                 data=json.dumps({"model": model or EMBED_MODEL, "input": texts}).encode())
    try:
        out = json.load(urllib.request.urlopen(req, timeout=timeout)).get("embeddings")
    except urllib.error.HTTPError as e:
        # the server's own words: a 400 is also a crashed runner, not only a missing model
        try:
            said = json.loads(e.read() or b"{}").get("error") or ""
        except (ValueError, OSError):
            said = ""
        hint = f" (`ollama pull {model or EMBED_MODEL}` on that host)" if e.code == 404 or "not found" in said else ""
        raise RecallError(f"{url or EMBED_URL} answered HTTP {e.code} for model {model or EMBED_MODEL}"
                          + (f": {said[:200]}" if said else "") + hint)
    except (urllib.error.URLError, OSError, ValueError) as e:
        raise RecallError(f"no embedding endpoint at {url or EMBED_URL} ({getattr(e, 'reason', e)})")
    if not out or len(out) != len(texts):
        raise RecallError(f"{url or EMBED_URL} returned {len(out or [])} vectors for {len(texts)} texts")
    return out


def recall_paths(index=None):
    base = index or INDEX
    return base + ".recall.f32", base + ".recall.json"


def _unit(v):
    import math
    n = math.sqrt(sum(x * x for x in v)) or 1.0
    return [x / n for x in v]


def build_recall(records):
    import array, base64, hashlib
    t0 = time.time()
    corpus = recall_corpus(records)
    vec_p, meta_p = recall_paths()
    status = {"count": 0, "denominator": len(corpus), "unit": "records with a recall vector",
              "model": EMBED_MODEL, "url": EMBED_URL}
    os.makedirs(RECALL_CACHE_DIR, exist_ok=True)
    cache_p = os.path.join(RECALL_CACHE_DIR, re.sub(r"[^A-Za-z0-9._-]", "_", EMBED_MODEL) + ".json")
    try:
        cache = json.load(open(cache_p))
    except (OSError, ValueError):
        cache = {}
    dpre = embed_prefix()[1]
    keys = [hashlib.sha256((RECALL_TEXT_VERSION + "\0" + dpre + recall_text(r)).encode()).hexdigest()[:24] for r in corpus]
    missing = [i for i, k in enumerate(keys) if k not in cache]
    try:
        for b in range(0, len(missing), RECALL_BATCH):
            chunk = missing[b:b + RECALL_BATCH]
            texts = [dpre + recall_text(corpus[i]) for i in chunk]
            try:
                vs = embed(texts, timeout=120)
            except RecallError:
                time.sleep(2)  # one retry: measured 2026-10-10, a batch failed while ollama swapped 3 models in memory
                vs = embed(texts, timeout=180)
            for i, v in zip(chunk, vs):
                cache[keys[i]] = base64.b64encode(array.array("f", _unit(v)).tobytes()).decode()
    except RecallError as e:
        for f in (vec_p, meta_p):  # never leave vectors from another model/corpus beside a new index
            if os.path.exists(f):
                os.remove(f)
        return dict(status, status=f"unavailable: {e}")
    tmp = cache_p + ".tmp"
    json.dump(cache, open(tmp, "w")); os.replace(tmp, cache_p)
    vecs = array.array("f")
    for k in keys:
        vecs.frombytes(base64.b64decode(cache[k]))
    dim = len(vecs) // max(len(keys), 1)
    with open(vec_p + ".tmp", "wb") as f:
        vecs.tofile(f)
    os.replace(vec_p + ".tmp", vec_p)
    json.dump({"model": EMBED_MODEL, "url": EMBED_URL, "dim": dim, "text_version": RECALL_TEXT_VERSION, "ids": [r["id"] for r in corpus],
               "hilt_version": HILT_VERSION, "built_at": int(time.time())}, open(meta_p, "w"))
    return dict(status, count=len(keys), dim=dim, embedded_now=len(missing), seconds=round(time.time() - t0, 2),
                floor=RECALL_MIN, floor_source=("HILT_RECALL_MIN" if os.environ.get("HILT_RECALL_MIN") else
                                                "tuned" if EMBED_MODEL.split(":")[0] in RECALL_FLOORS else "untuned default"),
                status="ok")


def recall_query(q, k=RECALL_TOP):
    """{results: [(score, id)], model, url, ms} or {unavailable: reason}. Never raises."""
    import array
    t0 = time.time()
    vec_p, meta_p = recall_paths()
    try:
        meta = json.load(open(meta_p))
    except (OSError, ValueError):
        return {"unavailable": "no recall vectors beside this index (the endpoint was down at `hilt build`, "
                               "or HILT_RECALL=0); rebuild with an embedding endpoint up"}
    if meta.get("model") != EMBED_MODEL:
        return {"unavailable": f"vectors were built with {meta.get('model')}, queries use {EMBED_MODEL}; rebuild"}
    if meta.get("text_version") != RECALL_TEXT_VERSION:
        return {"unavailable": f"vectors were built from text recipe {meta.get('text_version')}, this hilt builds "
                               f"{RECALL_TEXT_VERSION}; rebuild"}
    try:
        qv = _unit(embed([embed_prefix()[0] + q], timeout=4)[0])
    except RecallError as e:
        return {"unavailable": str(e)}
    vecs = array.array("f")
    with open(vec_p, "rb") as f:
        vecs.frombytes(f.read())
    dim, ids = meta["dim"], meta["ids"]
    if dim != len(qv) or len(vecs) != dim * len(ids):
        return {"unavailable": f"vector shape mismatch (index dim {dim}, query dim {len(qv)}); rebuild"}
    scored = []
    for i, rid in enumerate(ids):
        off = i * dim
        scored.append((sum(a * b for a, b in zip(qv, vecs[off:off + dim])), rid))
    scored.sort(reverse=True)
    top = [(round(sc, 3), rid) for sc, rid in scored[:k] if sc >= RECALL_MIN]
    return {"results": top, "model": EMBED_MODEL, "url": EMBED_URL, "ms": int((time.time() - t0) * 1000),
            "floor": RECALL_MIN, "best_below_floor": round(scored[0][0], 3) if scored and not top else None}


def build():
    global SETTINGS_SRC, TRAPS_SRC
    t0 = time.time()
    root, how = source_root()
    SETTINGS_SRC = os.environ.get("HILT_SETTINGS") or (root and os.path.join(root, "probes", "settings.json"))
    TRAPS_SRC = os.environ.get("HILT_TRAPS") or (root and os.path.join(root, "traps", "authored.json"))
    for what, src in (("settings", SETTINGS_SRC), ("traps", TRAPS_SRC)):
        if not src or not os.path.isfile(src):
            die(2, f"REFUSED build: authored {what} not found ({src or 'no source root'}). An "
                   "installed hilt has no probes/ or traps/ beside it; build once from the project "
                   "(`tools/hilt build`) so the index records its source root, or set HILT_ROOT. "
                   "Refusing rather than writing an index with zero settings.",
                {"verdict": "REFUSED", "why": "no-sources", "missing": what, "path": src})
    spotlight, bids = scan_bundle_ids()
    panes, s_panes, a = scan_panes()
    s_anchors = {"count": a["records"], "denominator": a["keys"],
                 "unit": f"Settings search anchors ({SEARCH_LPROJ} .searchTerms keys) indexed",
                 "files": a["files"], "unreadable": a["unreadable"]}
    intents, s_int = scan_intents(bids)
    apps, s_apps = scan_apps(bids)
    verbs, s_sdef = scan_sdef(apps)
    cli, s_cli = scan_cli()
    cli_auth, s_cli_auth = load_cli_authored(root)
    cli += [r for r in cli_auth if r["id"] not in {x["id"] for x in cli}]
    rc_sp, out_sp, _ = sh(["system_profiler", "-listDataTypes"], 20)
    taken = {r["x_argv"][-1] for r in cli if r.get("x_argv") and r["x_argv"][:1] == ["system_profiler"]}
    sp_gen, sp_skipped = sp_generated(set(out_sp.split()) if rc_sp == 0 else set(), taken)
    cli += sp_gen
    s_cli["system_profiler"] = {"generated": len(sp_gen), "authored": len(taken), "excluded": sp_skipped,
                               "denominator": len(out_sp.split()) - 2 if rc_sp == 0 else None}
    shortcuts, s_sc = scan_shortcuts()
    domains, s_dom = scan_domains(bids, spotlight)
    settings, s_set = load_settings(domains)
    state, s_state = scan_state(panes)
    native = [r for r in native_records() if coreaudio() is not None or not r["id"].startswith(("state.audio", "native.audio"))]
    records = settings + panes + apps + cli + state + native + verbs + shortcuts + intents
    for r in records:  # where a concept LIVES in Settings, beyond Apple's own search words
        if r["id"] in PANE_HOME:
            r["x_aliases"] = sorted(set(r.get("x_aliases", [])) | set(PANE_HOME[r["id"]]))
    tcc_map, s_tcc = load_tcc_map(root, panes)
    reqs, s_req = load_requirements(root)
    profs, s_prof = load_setup_profiles(root, tcc_map)
    known = {r["id"] for r in records}
    for r in records:  # an authored pointer to a pane must land on a derived one
        if r.get("x_fix") and r["x_fix"] not in known:
            s_state.setdefault("dangling_fix", []).append({"id": r["id"], "fix": r["x_fix"]})
            r["x_fix"] = None
    rc, ver, _ = sh(["sw_vers", "-productVersion"])
    rc, bld, _ = sh(["sw_vers", "-buildVersion"])
    proven = proven_runs(bld.strip())
    ids = {}
    by_id = {r["id"]: r for r in records}
    med = run_medians()
    for r in records:
        r["x_probe_kind"] = probe_kind(r)
        r["_find"] = find_fields(r)
        r["x_label"] = record_label(r, by_id)
        r["x_irreversible"], r["x_undo"] = record_safety(r)
        r.update({"x_" + k: v for k, v in record_latency(r, med).items()})
        if runnable(r):
            r["x_authority_confidence"] = "measured" if r["id"] in proven else "unverified"
            if r["id"] in proven:
                r["x_proven_at"] = proven[r["id"]]
        ids[r["id"]] = ids.get(r["id"], 0) + 1
    dup = sorted(i for i, n in ids.items() if n > 1)
    idx = {
        "hilt_contract": HILT_CONTRACT,
        "hilt_version": HILT_VERSION,
        "built_at": int(time.time()),
        "build_seconds": round(time.time() - t0, 2),
        "host": os.uname().nodename,
        "os": {"version": ver.strip(), "build": bld.strip(), "arch": os.uname().machine},
        "spotlight": spotlight,
        "full_disk_access": fda_status(),
        "source_root": root, "source_root_from": how,
        "sources": {"settings": s_set, "panes": s_panes, "anchors": s_anchors, "tcc_map": s_tcc, "state": s_state, "cli_authored": s_cli_auth, "requirements": s_req, "setup_profiles": s_prof, "apps": s_apps, "cli": s_cli,
                    "sdef": s_sdef, "shortcuts": s_sc, "intents": s_int, "domains": s_dom,
                    "bundle_ids": {"count": len(bids), "denominator": None,
                                   "unit": "bundle ids Spotlight indexes", "status": spotlight}},
        "duplicate_ids": dup,
        "records": records,
        "tcc_services": tcc_map,
        "requirements": reqs,
        "setup_profiles": profs,
        "domains": domains,
        "traps": load_traps(),
    }
    os.makedirs(os.path.dirname(INDEX), exist_ok=True)
    idx["sources"]["recall"] = build_recall(records) if RECALL_ON else \
        {"count": 0, "denominator": len(recall_corpus(records)), "unit": "records with a recall vector",
         "status": "off (HILT_RECALL=0)"}
    tmp = INDEX + ".tmp"
    with open(tmp, "w") as f:
        json.dump(idx, f)
    os.replace(tmp, INDEX)
    return idx


def load():
    try:
        idx = json.load(open(INDEX))
    except FileNotFoundError:
        die(2, f"REFUSED no index at {INDEX} — run `hilt build` first.")
    if idx.get("hilt_contract") != HILT_CONTRACT:
        die(2, f"REFUSED index speaks contract {idx.get('hilt_contract')}, this tool speaks "
               f"{HILT_CONTRACT} — run `hilt build`.")
    # An index built by another hilt version can be missing what THIS version
    # authored (zil@mbp #hilt 244, 2026-10-03: a 0.6.6 index answered `setup --list`
    # on 0.6.9 with `core` only, no signal). Same contract, different version:
    # rebuild in place when the sources this build would read are the ones the
    # index was built from (the base project, or an installed copy pointing at
    # it); otherwise refuse with the fix — a worktree must never rebuild the
    # shared index under the base's name (AGENTS.md: build from base, never a
    # worktree). HILT_NO_REBUILD=1 turns the rebuild into the refusal (tests).
    if idx.get("hilt_version") != HILT_VERSION:
        root, how = source_root()
        rec = idx.get("source_root")
        same = root and (not rec or os.path.realpath(root) == os.path.realpath(rec))
        if same and os.environ.get("HILT_NO_REBUILD") != "1":
            print(f"hilt: index was built by hilt {idx.get('hilt_version')}, this is {HILT_VERSION}: rebuilding "
                  f"from {root} ({how})", file=sys.stderr)
            return build()
        die(2, f"REFUSED index at {INDEX} was built by hilt {idx.get('hilt_version')}; this is {HILT_VERSION}"
               + (f" and its sources ({root}) are not the index's ({rec})" if root and rec else "")
               + " — run `hilt build` from the base project.",
            {"verdict": "REFUSED", "why": "index-stale", "index_version": idx.get("hilt_version"),
             "hilt_version": HILT_VERSION, "fix_command": "hilt build"})
    return idx


# ---------------------------------------------------------------- output

JSON = False


def emit(obj, text, code=0):
    if JSON:
        print(json.dumps(obj, indent=2, default=str))
    else:
        print(text)
    sys.exit(code)


def die(code, text, obj=None):
    emit(obj or {"verdict": text.split()[0], "detail": text}, text, code)


# ---------------------------------------------------------------- verbs

def cmd_build(_):
    idx = build()
    n = len(idx["records"])
    emit({"verdict": "BUILT", "built": INDEX, "records": n, "seconds": idx["build_seconds"]},
         f"built {INDEX}: {n} records in {idx['build_seconds']}s "
         f"(`hilt coverage` for every count with its denominator)")


def by_kind(idx):
    c = {}
    for r in idx["records"]:
        c[r["kind"]] = c.get(r["kind"], 0) + 1
    return c


def holes(idx):
    h = []
    if idx["spotlight"] != "enabled":
        h.append({"hole": "spotlight", "detail": f"Spotlight indexing {idx['spotlight']}: owners "
                  "answers UNVERIFIABLE, never UNOWNED"})
    fda = fda_status()  # live: the index's value is what the BUILD process saw, which may have been a sandbox
    if fda != "granted":
        h.append({"hole": "tcc", "detail": f"Full Disk Access {fda} for this process"
                  + (" (the TCC path does not resolve from here: a sandboxed shell; the host app itself may hold it — "
                     "`hilt setup --check` from the host answers)" if fda == "hidden" else
                     ": privacy permission STATE is unreadable; privacy panes are human-required")})
    rs = idx["sources"].get("recall") or {}
    if rs and rs.get("status") != "ok":
        h.append({"hole": "recall", "detail": f"find by meaning {rs.get('status')} — word matching only"})
    for c, why in idx["sources"]["cli"].get("holes", {}).items():
        h.append({"hole": f"cli:{c}", "detail": why})
    for c in idx["sources"]["cli"].get("missing", []):
        h.append({"hole": f"cli:{c}", "detail": "expected Apple CLI absent"})
    h.append({"hole": "run:application.verb", "detail": "sdef verbs are refused by run until a cut "
              "marshals typed arguments into AppleScript without templating text (spec §9)"})
    h.append({"hole": "run:untyped-params", "detail": "a param the index did not type (a string with "
              "no enum and no path rules, e.g. an IP address) is refused by run, never guessed"})
    h.append({"hole": "privacy-state:local-network+accessories", "detail": "Local Network and USB/"
              "Thunderbolt accessory approvals are not in TCC.db and have no Privacy search anchor on "
              "this OS; where their decisions live is not located, so `permissions` cannot report "
              "them (the Security anchor covers the accessory setting's pane)"})
    h.append({"hole": "intent-actuator", "detail": "no public shell door invokes an App Intent; "
              "intent records are describe-only"})
    for r in idx["sources"].get("state", {}).get("dangling_fix", []):
        h.append({"hole": f"fix:{r['id']}", "detail": f"points at {r['fix']}, which this box's index lacks"})
    for r in idx["sources"].get("setup_profiles", {}).get("rejected", []):
        h.append({"hole": f"setup-profile:{r['id']}", "detail": "authored row rejected: " + r["why"]})
    for r in idx["sources"].get("requirements", {}).get("rejected", []):
        h.append({"hole": f"requirement:{r['id']}", "detail": "authored row rejected: " + r["why"]})
    for r in idx["sources"].get("tcc_map", {}).get("rejected", []):
        h.append({"hole": f"tcc-map:{r['id']}", "detail": "authored row rejected: " + r["why"]})
    if idx["sources"].get("tcc_map", {}).get("status"):
        h.append({"hole": "tcc-map", "detail": idx["sources"]["tcc_map"]["status"]})
    for r in idx["sources"]["settings"].get("rejected", []):
        h.append({"hole": f"setting:{r['id']}", "detail": "authored row rejected: " + r["why"]})
    return h


def cmd_orient(_):
    idx = load()
    k = by_kind(idx)
    age = int(time.time()) - idx["built_at"]
    h = holes(idx)
    app = responsible_app()
    try:
        su = json.load(open(SETUP)).get(app) if app else None
    except (OSError, ValueError):
        su = None
    stale = []
    if su:
        if su.get("os_build") and su["os_build"] != idx["os"]["build"]:
            stale.append(f"macOS {su['os_build']}→{idx['os']['build']}")
        v = host_version(app) if app else None
        if su.get("app_version") and v and su["app_version"] != v:
            stale.append(f"{app} {su['app_version']}→{v}")
    setup_line = (f"setup for {app}: {su['verdict']} ({time.strftime('%Y-%m-%d', time.localtime(su['ts']))})"
                  + (f" — RE-CHECK: {', '.join(stale)} since setup (`hilt setup dev --check`)" if stale else "")
                  if su else f"setup for {app or 'no responsible app'}: never run — `hilt setup`")
    lines = [f"hilt contract {idx['hilt_contract']} · {idx['host']} · macOS {idx['os']['version']} "
             f"({idx['os']['build']}, {idx['os']['arch']}) · index {age // 60} min old",
             f"records {len(idx['records'])}: " + ", ".join(f"{v} {kk}" for kk, v in
                                                            sorted(k.items(), key=lambda x: KIND_RANK.get(x[0], 9))),
             f"spotlight {idx['spotlight']} · full disk access {idx['full_disk_access']}",
             setup_line,
             f"authored sources {idx.get('source_root')} ({idx.get('source_root_from')})",
             f"holes ({len(h)}):"] + [f"  - {x['hole']}: {x['detail']}" for x in h] + [
             "verbs: find <q> [--criteria] · describe <id> · run <id> [args] · permissions [app] · vocab · inventory · setup [core|dev|voice|desk] [--check|--pppc|--list] · setup reset <service> · learn start <label>|diff|confirm · owners <domain|plist> · coverage · traps · build",
             "exit codes: 0 answer · 1 run failed · 2 refused/unknown · 3 VACUOUS · 4 UNVERIFIABLE · 5 run mismatched"]
    emit({"verdict": "OK", "contract": idx["hilt_contract"], "host": idx["host"], "os": idx["os"],
          "index_age_s": age, "records": len(idx["records"]), "by_kind": k,
          "spotlight": idx["spotlight"], "full_disk_access": fda_status(), "full_disk_access_at_build": idx["full_disk_access"],
          "source_root": idx.get("source_root"), "source_root_from": idx.get("source_root_from"), "holes": h,
          "setup": {"app": app, "record": su, "stale": stale}},
         "\n".join(lines))


def cmd_coverage(_):
    idx = load()
    s = idx["sources"]
    k = by_kind(idx)
    rows = []

    def row(name, n, d, unit, extra=""):
        rows.append({"source": name, "count": n, "denominator": d, "unit": unit, "extra": extra})

    row("settings", s["settings"]["count"], s["settings"]["denominator"], s["settings"]["unit"],
        f"rejected {len(s['settings']['rejected'])}")
    row("panes", s["panes"]["count"], s["panes"]["denominator"], s["panes"]["unit"])
    row("anchors", s["anchors"]["count"], s["anchors"]["denominator"], s["anchors"]["unit"],
        f"from {s['anchors']['files']} files, {s['anchors']['unreadable']} unreadable")
    if "tcc_map" in s:
        row("tcc_map", s["tcc_map"]["count"], s["tcc_map"]["denominator"], s["tcc_map"]["unit"],
            f"rejected {len(s['tcc_map'].get('rejected', []))}")
    if "setup_profiles" in s:
        row("setup", s["setup_profiles"]["count"], s["setup_profiles"]["denominator"], s["setup_profiles"]["unit"],
            f"profiles {s['setup_profiles'].get('profiles')}, rejected {len(s['setup_profiles'].get('rejected', []))}")
    if "requirements" in s:
        row("requirements", s["requirements"]["count"], s["requirements"]["denominator"],
            s["requirements"]["unit"], f"rejected {len(s['requirements'].get('rejected', []))}, "
            f"formulas checked against brew: {s['requirements'].get('formulas_checked')}")
    if "state" in s:
        row("state", s["state"]["count"], s["state"]["denominator"], s["state"]["unit"],
            f"skipped {len(s['state']['skipped'])}")
    row("apps", s["apps"]["count"], s["apps"]["denominator"], s["apps"]["unit"],
        f"without bundle id {s['apps']['without_bundle_id']}")
    row("sdef", s["sdef"]["count"], s["sdef"]["denominator"], s["sdef"]["unit"],
        f"verbs {s['sdef']['verbs']}, failed {s['sdef']['failed']}")
    row("intents", s["intents"]["count"], None, s["intents"]["unit"],
        f"from {s['intents']['bundles']} bundles, {s['intents']['params_enum_or_dynamic']} params "
        f"typed enum/dynamic, {s['intents']['unreadable']} unreadable")
    row("cli", s["cli"]["count"], s["cli"]["denominator"], s["cli"]["unit"],
        f"networksetup verbs {s['cli']['networksetup_verbs']}; missing {s['cli']['missing'] or 'none'}")
    if s["cli"].get("system_profiler"):
        sp = s["cli"]["system_profiler"]
        row("system_profiler", sp["generated"] + sp["authored"], sp["denominator"], "data types with a read row",
            f"authored {sp['authored']}, generated {sp['generated']}, excluded by measurement {len(sp['excluded'])}")
    if "recall" in s:
        rc_ = s["recall"]
        row("recall", rc_["count"], rc_.get("denominator"), rc_["unit"],
            f"{rc_.get('model', '-')} via {rc_.get('url', '-')}: {rc_['status']}"
            + (f", floor {rc_['floor']} ({rc_['floor_source']})" if rc_.get("floor") is not None else ""))
    if "cli_authored" in s:
        ca = s["cli_authored"]
        row("cli_authored", ca["count"], ca["denominator"], ca["unit"],
            f"reads {ca.get('reads', 0)}, setters {ca.get('setters', 0)}, sudo {ca.get('sudo', 0)}; "
            f"rejected {len(ca['rejected'])}, skipped {len(ca['skipped'])}")
    row("shortcuts", s["shortcuts"]["count"], s["shortcuts"]["denominator"], s["shortcuts"]["unit"])
    row("domains", s["domains"]["count"], s["domains"]["denominator"], s["domains"]["unit"],
        f"with plist {s['domains']['with_plist']}, owner resolved {s['domains']['owner_resolved']}")
    run_ok = [r for r in idx["records"] if r.get("x_authority_confidence")]
    meas = [r for r in run_ok if r["x_authority_confidence"] == "measured"]
    per = {}
    for r in run_ok:
        m, n = per.get(r["kind"], (0, 0))
        per[r["kind"]] = (m + (r in meas), n + 1)
    row("authority", len(meas), len(run_ok), "runnable records proven by a verified/query run on this OS build",
        ", ".join(f"{kk} {m}/{n}" for kk, (m, n) in sorted(per.items())))
    probes = {}
    for r in idx["records"]:
        probes[r["x_probe_kind"]] = probes.get(r["x_probe_kind"], 0) + 1
    total = len(idx["records"])
    arith_ok = sum(k.values()) == total == sum(probes.values())
    lines = [f"{'source':<10} {'count':>6} / {'denom':<6} unit"]
    for r in rows:
        d = "—" if r["denominator"] is None else r["denominator"]
        lines.append(f"{r['source']:<10} {r['count']:>6} / {str(d):<6} {r['unit']}"
                     + (f"  ({r['extra']})" if r["extra"] else ""))
    lines.append(f"records {total} = " + " + ".join(f"{v} {kk}" for kk, v in sorted(k.items())))
    lines.append("probe kinds: " + ", ".join(f"{v} {kk}" for kk, v in sorted(probes.items())))
    lines.append("arithmetic " + ("OK" if arith_ok else "BROKEN — kinds and probe kinds do not sum to records"))
    if idx["duplicate_ids"]:
        lines.append(f"DUPLICATE ids {len(idx['duplicate_ids'])}: {idx['duplicate_ids'][:5]}")
    emit({"verdict": "OK" if arith_ok else "BROKEN", "sources": rows, "records": total,
          "by_kind": k, "probe_kinds": probes,
          "arithmetic_ok": arith_ok, "duplicate_ids": idx["duplicate_ids"]},
         "\n".join(lines), 0 if arith_ok else 2)


def find_words(f):
    """A field as its normalized words, space-joined. Computed at BUILD into
    each record's `_find` (per-query splitting was ~0.14 s of a 0.2 s find, on
    a voice path). A possessive would leave a one-letter word "s" to splice
    onto the next ("options's show" -> "s"+"sh"...), so it goes first."""
    return " ".join(w for w in (norm(x) for x in words(re.sub(r"['\u2019]s\b", "", f)).split()) if w)


def find_fields(r):
    return r.get("_find") or [find_words(f) for f in [r["id"], r["outcome"]] + r.get("x_aliases", [])
                              + ([r["x_situation"]] if r.get("x_situation") else []) if f]


@functools.lru_cache(maxsize=None)
def _word_runs(f):
    """A pre-normalized field as (space-free text, word starts, word ends)."""
    ws = f.split()
    starts, ends, pos = set(), set(), 0
    for w in ws:
        starts.add(pos)
        pos += len(w)
        ends.add(pos)
    return "".join(ws), frozenset(starts), frozenset(ends)


def word_hit(tok, fields):
    """True when `tok` starts at a WORD boundary of some field, spaces and
    punctuation ignored inside the run ("wifi" hits "Wi-Fi", "dock size" hits
    "dock tilesize" only via its alias). Matching inside the space-stripped
    blob made "ssh" hit "scroll ba[rs sh]ow" and "usb" hit "stat[us b]ar"."""
    nt = norm(tok)
    if not nt:
        return True
    for f in fields:
        joined, starts, ends = _word_runs(f)
        i = joined.find(nt)
        while i != -1:
            # A short token (ip, dns, usb) must also END on a word boundary, or
            # "ip" becomes the start of "iPhone".
            if i in starts and (len(nt) > 3 or i + len(nt) in ends):
                return True
            i = joined.find(nt, i + 1)
    return False


# Words that carry no capability in a spoken or typed request. A CLOSED list:
# they are dropped only from the per-word tiers (2 and 3); tiers 0/1 still see
# the whole query, so an alias like "open slack" or "my ip" matches exactly.
STOPWORDS = frozenset("""a an the is are am was were be been can could would will should you your me my
i it its this that these those what whats which who why how does do did please show tell check if
of for to in on off at and or with from about up keep keeps asking stuff thing things turned turn
get give some any there here now just hey okay ok uh um like see let lets want need
make sorry never mind open launch start switch go bring""".split())
# Verbs an ASR glues onto the name that follows ("OpenPMox", "LaunchGosty").
GLUED_VERB = re.compile(r"^(open|launch|start|switch)([a-z].{2,})$")


def content_tokens(toks):
    return [t for t in toks if norm(t) and t.strip("'?.!,").replace("'", "") not in STOPWORDS] or toks


def score(r, q, qn, toks, partial=False):
    hay_al = [r["id"].lower()] + [a for a in r.get("x_aliases", []) if a]
    qc = " ".join(toks)  # the query without its filler words
    if q in hay_al or qn in (norm(a) for a in hay_al) or (qc != q and qc in hay_al):
        exact = q in hay_al or qn in (norm(a) for a in hay_al)
        # An anchor's search words are Apple's "also matches" list: "file sharing"
        # is a search word of Firewall but the TITLE of File Sharing. Title first.
        if r.get("x_anchor") is not None and q not in r.get("x_titles", []) and qn != norm(r["id"]):
            # …an anchor whose own id segment IS the query ("hotcorners") beats
            # search words, but stays below a top-level page's exact hit ("wifi").
            return 0.25 if qn == norm(r["id"].rsplit(".", 1)[-1]) else 0.5
        # the person's WHOLE words beat the same words with filler stripped: "lock the
        # screen" is the lock action's alias; the Lock Screen page only matches "lock screen"
        return 0 if exact else 0.1
    out = r["outcome"].lower()
    if len(qn) <= 3:  # a short query prefixes a WORD ("ip address"), never a longer one ("iphone")
        pre = lambda a: a == q or a.startswith(q + " ")
    else:
        pre = lambda a: a.startswith(q) or norm(a).startswith(qn)
    if pre(out) or any(pre(a) for a in hay_al):
        return 1
    fields = find_fields(r)
    hit = sum(1 for t in toks if word_hit(t, fields))
    if hit == len(toks):
        return 2
    if partial and len(toks) > 1 and hit * 2 >= len(toks):
        # Partial: some content words match. Ranked by the share that missed,
        # so "why does cmux keep asking for permission" still reaches both the
        # permissions record and cmux, below every full match.
        # Only for --criteria (a chooser with an explicit `none` follows);
        # plain find stays all-words, so nonsense is still NONE.
        return 3 + round(1 - hit / len(toks), 3)
    return None


CRITERIA_TOP = 8
NONE_MEANING = "none of these: not a request this Mac can serve; or chatter; or unclear"


def criterion(text):
    """A meaning rift can carry: `rift decide --criteria` splits on ',' and '='
    (rift cmd_decide.rs:73, and its MCP path re-joins then re-splits), so
    neither may appear inside a meaning."""
    return re.sub(r"\s+", " ", text.replace(",", ";").replace("=", " is ")).strip()


def emit_criteria(q, recs, extra=None):
    """find --criteria: the top candidates as rift decide criteria (id=meaning)
    plus an explicit `none`, because rift always returns one of the keys — it
    has no null. Text mode prints ONLY the --criteria argument, so
    `rift decide --state "$T" --criteria "$(hilt find --criteria $T)"` composes."""
    crit = {}
    for r in recs:
        if "," in r["id"] or "=" in r["id"]:
            continue
        crit[r["id"]] = criterion(r["outcome"] + (" [a human finishes in Settings]"
                                                  if r["authority"] == "human-required" else ""))
    crit["none"] = NONE_MEANING
    arg = ",".join(f"{k}={v}" for k, v in crit.items())
    emit({"verdict": "FOUND" if len(crit) > 1 else "NONE", "query": q, "criteria": crit,
          "criteria_arg": arg, "top": CRITERIA_TOP, **(extra or {})}, arg)


def unglue(toks, records):
    """Split a glued launch verb off the name after it ("openwarp." -> "open
    warp."), measured in Whisper output 2026-09-23. Only when the glued
    token itself matches nothing, so "launchpad" (an app) stays whole."""
    out = []
    for t in toks:
        m = GLUED_VERB.match(norm(t))
        if m and not any(word_hit(t, find_fields(r)) for r in records):
            out += [m.group(1), m.group(2)]
        else:
            out.append(t)
    return out


FUZZY_MIN = 0.75


def fuzzy_app(r, toks):
    """Chooser-only tier for ASR near-misses of an app NAME ("Ghosty" ->
    Ghostty, "Itern" -> iTerm, "dmux" -> cmux): the best similarity of any
    content word, or of adjacent word pairs, to the app's own name. Ranked
    between full matches (2) and partial ones (3); rift judges it with `none`
    beside it, so a false near-miss costs one wrong candidate, not an action."""
    name = norm(r["outcome"][len("open "):] if r["outcome"].startswith("open ") else r["outcome"])
    if len(name) < 3:
        return None
    grams = [norm(t) for t in toks] + [norm(a + b) for a, b in zip(toks, toks[1:])]
    best = max((difflib.SequenceMatcher(None, g, name).ratio() for g in grams if len(g) >= 3), default=0)
    return round(2.5 + (1 - best), 3) if best >= FUZZY_MIN else None


# ---- a direct request carries its own arguments (Mark, 2026-09-28: "if it's direct we
# should offer outcomes, not three questions"). find reads two kinds from the words and
# returns them as `args` with the words that justified them; the CALLER decides to run.
QUESTION_START = re.compile(r"^(is|are|am|was|were|what|whats|what's|how|which|does|did|can|could|will|do (i|you|we|they))\b")
# A concept's HOME page. Apple's search words attach "do not disturb" to Control
# Center's "show in the menu bar" option too; "go to do not disturb" opened that
# (Mark, 2026-09-28) instead of Focus, where Do Not Disturb is configured.
PANE_HOME = {"system.pane.focus": ["do not disturb", "dnd", "focus modes", "do not disturb settings"]}
NAV_START = re.compile(r"^(go to|goto|open|launch|show me|take me to|navigate to|bring up|switch to)\b")
# Mark, 2026-09-28: "opening apps should be one surface, open and go to, another".
APP_VERB = re.compile(r"^(open|launch|switch to|bring up)\b")
MENU_BAR_WORDS = ("menu bar", "control center", "status icon", "menubar")


def menu_bar_option(r):
    """A Control Center 'show X in the menu bar' option: about an ICON, not about X."""
    return r["kind"] == "system.pane" and r["id"].startswith("system.pane.controlcenter.") and \
        "menu bar" in ((r.get("x_titles") or [""])[0])


SAID_VERBS = {"hide", "show", "mute", "unmute", "dim", "brighten"}  # only a record's own `say` map types these
ON_WORDS = {"on", "enable", "activate", "start", "set"}
OFF_WORDS = {"off", "disable", "deactivate", "stop", "end"}


def query_host(raw):
    """(host peer name or None, raw words without the host phrase). A tailnet Mac named
    in the query ("on my macbook pro", "the mini") — only an UNAMBIGUOUS phrase counts."""
    if not any(w in MODEL_WORDS or w in ("mbp", "mba", "here", "machine") or "-" in w for w in raw):
        return None, raw, None
    peers = tailnet_macs() or []
    found = []
    for p in peers:
        for ph in host_phrases(p) | {p["name"].lower()}:
            n = len(ph.split())
            for i in range(len(raw) - n + 1):
                if [w.strip("?.!,'") for w in raw[i:i + n]] == ph.split():
                    found.append((n, i, p, ph))
    if not found:
        return None, raw, None
    best = max(f[0] for f in found)
    top = {f[2]["name"]: f for f in found if f[0] == best}
    if len(top) != 1:
        return None, raw, None  # "macbook" with a Pro and an Air: ambiguous, name nobody
    n, i, p, ph = next(iter(top.values()))
    j = i
    while j > 0 and raw[j - 1] in ("my", "the", "on", "of", "from", "for", "at"):
        j -= 1
    return p, raw[:j] + raw[i + n:], " ".join(raw[j:i + n])


def query_value(raw):
    """('on'|'off'|None, the words that said so). Questions never carry a value."""
    q = " ".join(raw)
    if QUESTION_START.match(q):
        return None, None
    for w in raw:  # a setting's own verbs ("hide the dock"): resolved per record in record_args
        if w.strip("?.!,") in SAID_VERBS:
            return "said:" + w.strip("?.!,"), [w.strip("?.!,")]
    words_ = {w.strip("?.!,") for w in raw}
    on, off = words_ & ON_WORDS, words_ & OFF_WORDS
    if bool(on) == bool(off):
        return None, None
    return ("on", sorted(on)) if on else ("off", sorted(off))


UP_WORDS = {"up", "louder", "higher", "increase", "raise", "brighter", "brighten"}
DOWN_WORDS = {"down", "quieter", "lower", "decrease", "reduce", "softer", "dimmer", "darker", "dim"}
AUDIO_WORDS = {"output", "speaker", "speakers", "sound", "audio", "headphones", "play"}


def query_level(raw):
    """('50'|'up'|'down'|None, words): a volume the words name. Questions carry none."""
    if QUESTION_START.match(" ".join(raw)):
        return None, None
    q = " ".join(raw)
    m = re.search(r"\b(100|[1-9]?\d)\s*(%|percent)?(?=\s|$)", q)
    if m:
        return m.group(1), [m.group(0)]
    ws = {w.strip("?.!,") for w in raw}
    if ws & UP_WORDS and not ws & DOWN_WORDS:
        return "up", sorted(ws & UP_WORDS)
    if ws & DOWN_WORDS and not ws & UP_WORDS:
        return "down", sorted(ws & DOWN_WORDS)
    return None, None


def query_device(raw):
    """(fragment, words) for "switch output to airpods" / "play sound through the dock":
    only when the fragment names ONE live output device or ONE paired Bluetooth headset."""
    if not {w.strip("?.!,") for w in raw} & AUDIO_WORDS:
        return None, None
    m = re.search(r"\b(?:to|through|via|on)\s+(?:my\s+|the\s+)?(.+)$", " ".join(raw))
    if not m:
        return None, None
    frag = m.group(1).strip("?.!, ")
    live = [d for d in audio_devices() or [] if d["output"] and len(norm(frag)) >= 3 and norm(frag) in norm(d["name"])]
    if len(live) == 1 or bt_audio_match(frag):
        return frag, m.group(0).split()
    return None, None


TRAIL_CONNECTORS = {"called", "named", "for", "on", "to", "the", "my", "at", "of", "a", "an", "app", "port", "host"}
TRAIL_UNITS = {"minutes", "minute", "mins", "min", "percent", "%", "gb", "gigabytes", "seconds", "secs"}


def cli_trailing_arg(r, raw):
    """CUT H: "force quit safari" / "what's on port 9000" / "find a file called budget" /
    "keep my mac awake for 30 minutes". When one of the row's own aliases (or its
    outcome's first words) LEADS the query, the words after it are the row's ONE
    param — if they type. Returns (param name, value, words consumed) or None."""
    if not r.get("x_cli_authored"):
        return None
    ps = [pp for pp in r.get("x_params") or [] if pp.get("typed_by") != "tailnet.mac" and not pp.get("optional")]
    if len(ps) != 1 or ps[0].get("type") == "path":
        return None  # exactly one REQUIRED param; optional ones take their defaults
    p = ps[0]
    q = [w.strip("?.!,") for w in raw]
    qn = " ".join(q)
    for alias in sorted(r.get("x_aliases") or [], key=len, reverse=True):
        aw = alias.lower().split()
        if q == aw and p.get("enum"):
            # the alias IS the query and names the enum value inside it ("restart the dock" -> Dock)
            canon = {str(e).lower(): str(e) for e in p["enum"]}
            hit = [canon[w] for w in q if w in canon]
            if len(hit) == 1:
                return p["name"], hit[0], q
            continue
        if len(q) <= len(aw) or q[:len(aw)] != aw:
            continue
        rest = [w for w in q[len(aw):]]
        while rest and rest[0] in TRAIL_CONNECTORS:
            rest.pop(0)
        while rest and rest[-1] in TRAIL_UNITS:
            rest.pop()
        if not rest:
            continue
        val = " ".join(rest)
        typ, tb, enum, rng = p.get("type"), p.get("typed_by"), p.get("enum"), p.get("range")
        ok = False
        if enum:
            canon = {str(e).lower(): str(e) for e in enum}
            ok = val in canon
            if ok:
                val = canon[val]
        elif typ == "integer":
            ok = bool(re.fullmatch(r"\d+", val)) and (not rng or rng[0] <= int(val) <= rng[1])
        elif tb == "net.host":
            ok = bool(NET_HOST.fullmatch(val)) and ".." not in val and len(rest) == 1
        elif tb == "text.filename":
            ok = bool(TEXT_FILENAME.fullmatch(val))
        elif tb == "app.running":
            vn = norm(val)
            ok = any(vn in {norm(x) for x in a.get("x_aliases", [])} or vn == norm(a["outcome"][len("open "):])
                     for a in load()["records"] if a["kind"] == "application.launch")
        elif tb == "diskutil.volume":
            ok = any(val == (v["name"] or "").lower() or val == v["id"].lower() for v in diskutil_volumes() or [])
        elif tb == "net.ip":
            ok = bool(NET_IP4.fullmatch(val)) or (":" in val and bool(NET_IP6.fullmatch(val)))
        elif tb == "net.cidr":
            ok = len(rest) == 1 and net_cidr(val) is not None
        elif tb == "networksetup.service":
            ok = any(norm(x) == norm(val) for x in ns_services())
        elif tb == "networksetup.device":
            ok = val in ns_devices()
        elif tb == "launchd.label":
            ok = len(rest) == 1 and any(val.lower() == l.lower() or val.lower() in l.lower() for l in launchd_labels())
        elif tb == "text.token":
            ok = len(rest) == 1 and bool(TEXT_TOKEN.fullmatch(val))
        elif tb == "text.subsystem":
            ok = len(rest) == 1 and bool(TEXT_SUBSYSTEM.fullmatch(val))
        elif tb == "defaults.domain":
            ok = len(rest) == 1 and any(x.lower() == val for x in (load().get("domains") or {}))
        elif tb in ("app.process", "app.bundle", "app.path"):
            vn = norm(val)
            ok = any(vn in {norm(x) for x in a.get("x_aliases", [])} or vn == norm(a["outcome"][len("open "):])
                     for a in load()["records"] if a["kind"] == "application.launch")
        if ok:
            return p["name"], val, q[:len(aw)] + rest
    return None


def record_args(r, host, value, level=None, device=None):
    """The arguments this record can take from the query, typed by its own params."""
    out = {}
    ps = r.get("x_params") or []
    if host and any(pp.get("typed_by") == "tailnet.mac" for pp in ps):
        out["host"] = None if host["self"] else host["name"]
    first = next((pp for pp in ps if pp.get("typed_by") != "tailnet.mac"), None)
    if first and first.get("typed_by") in ("audio.level", "display.level"):
        if level:
            out[first["name"]] = level
        return out
    if first and first.get("typed_by") == "audio.output":
        if device:
            out[first["name"]] = device
        return out
    if value and first and value[0].startswith("said:"):
        v = (r.get("x_say") or {}).get(value[0][5:])
        if v is not None:
            out[first["name"]] = str(v).lower()
        return out
    if value and first:
        enum = [str(e).lower() for e in (first.get("enum") or [])]
        if first.get("type") == "boolean":
            out[first["name"]] = "true" if value[0] == "on" else "false"
        elif value[0] in enum:
            out[first["name"]] = value[0]
    return out


def cmd_find(args):
    if not args:
        die(2, "REFUSED find needs a query, e.g. `hilt find wifi`")
    limit = 10 ** 6 if "--all" in OPTS else 15
    idx = load()
    q = " ".join(args).lower().strip()
    chooser = "--criteria" in OPTS
    raw = q.split()
    if chooser:
        raw = unglue(raw, idx["records"])
        q = " ".join(raw)
    host, raw_nohost, host_words = query_host(raw)
    value, value_words = query_value(raw_nohost)
    level, level_words = query_level(raw_nohost)
    device, device_words = query_device(raw_nohost)
    question = bool(QUESTION_START.match(" ".join(raw)))
    navigate = bool(NAV_START.match(" ".join(raw))) and not (value or level or device)
    want_app = bool(APP_VERB.match(" ".join(raw)))  # else "go to" / "take me to": a page
    about_menu_bar = any(w in " ".join(raw) for w in MENU_BAR_WORDS)
    if navigate:  # the thing is what follows the verb: "go to do not disturb" -> "do not disturb"
        rest = NAV_START.sub("", " ".join(raw_nohost)).strip()
        if rest:
            q, raw_nohost = rest, rest.split()
    if host:
        q = " ".join(raw_nohost)
    qn, toks = norm(q), content_tokens(raw_nohost)
    if value and not value.startswith("said:"):  # "set", "enable": the verb picks the value; the thing is the rest
        toks = [t for t in toks if t.strip("?.!,") not in ON_WORDS | OFF_WORDS] or toks
    if level:  # "50 percent" / "louder": the amount, not the thing
        toks = [t for t in toks if not re.fullmatch(r"\d+%?|percent", t.strip("?.!,"))
                and t.strip("?.!,") not in UP_WORDS | DOWN_WORDS] or toks
    if device:  # "to airpods": the device, not the thing
        dw = {norm(w) for w in device.split()}
        toks = [t for t in toks if norm(t) not in dw] or toks
    cue = value or level or device
    hits = []
    trailing = None
    for r in idx["records"]:
        ta = cli_trailing_arg(r, raw_nohost) if not question or r["kind"] == "system.state" else None
        if ta:
            # the row's alias leads and its one param took the rest: top tier, the value read
            s, a = 0, {ta[0]: ta[1]}
            trailing = trailing or ta[2]
            if host and any(pp.get("typed_by") == "tailnet.mac" for pp in r.get("x_params") or []):
                a["host"] = None if host["self"] else host["name"]
            hits.append((s, 0, KIND_RANK.get(r["kind"], 9), r["id"], r, a))
            continue
        s = score(r, q, qn, toks, partial=chooser)
        if s is None and chooser and r["kind"] == "application.launch":
            s = fuzzy_app(r, toks)
        if s is None:
            continue
        a = record_args(r, host, (value, value_words) if value else None, level, device)
        if host and host.get("self") and "host" not in a:
            pass  # "this mac" / "here" is THIS Mac: every local record applies; nothing is filtered
        elif host and "host" not in a:
            # a tailnet row whose param is a peer name takes the Mac the words named
            nh = next((pp for pp in r.get("x_params") or [] if pp.get("typed_by") == "net.host"), None)
            if nh and r.get("x_situation") == "tailnet" and not host["self"]:
                a = dict(a, **{nh["name"]: host["name"]})
            else:
                continue  # the query names another Mac; this record cannot reach it
        if value and value.startswith("said:") and len(a) - ("host" in a) > 0:
            s = 0  # the setting's OWN verb plus its subject ("show the dock"): the strongest reading
        if menu_bar_option(r) and not about_menu_bar:
            s = s + 0.4  # below the thing itself, unless the menu bar was asked about
        if r["kind"] == "system.pane" and re.search(r"\.(tutorial|tips?)$", r["id"]) and \
                not any(w in ("tutorial", "tips", "tip") for w in raw):
            s = s + 0.4  # a tutorial is never the target unless asked for (Zil handoff #4)
        if r["kind"] == "application.verb" and r["id"].split(".do.")[-1] not in SAFE_VERBS:
            s = s + 0.4  # a scripting verb run REFUSES (not on the allowlist) ranks below a door that acts
        if r["kind"] == "application.launch" and s >= 2 and toks and \
                all(norm(t) in [norm(w) for w in r["outcome"][len("open "):].split()] for t in toks):
            s = 0.5 if want_app else 1.5  # the words ARE the app's name ("launch chrome"), not a word in a bundle id (#6)
        # Within a tier: a question prefers a read, a command prefers the record whose
        # own param took the value.
        mood = (0 if r["kind"] == "system.state" else 1) if question else \
               (0 if len(a) - ("host" in a) > 0 else 1) if cue else \
               ((0 if r["kind"] == ("application.launch" if want_app else "system.pane") else
                 0.5 if r["kind"] in ("system.pane", "application.launch") else 1) if navigate else 0)
        hits.append((s, mood, KIND_RANK.get(r["kind"], 9) + (0.5 if r.get("x_background") else 0), r["id"], r, a))
    hits.sort(key=lambda x: x[:4])
    hits = [(h[0], h[2], h[3], h[4], h[5]) for h in hits]
    # one NAME, several apps (Apple Messages / Google Messages Chrome app): the one this
    # person actually uses, by Spotlight's use count, when it is at least 5x the other.
    use_decided = None
    if hits:
        top = [h for h in hits if h[0] == hits[0][0]]
        # A NULL count (never used since Spotlight indexed it: an OS update replaces system apps
        # and resets their counters, measured on macOS 27) reads as 0, but only when a sibling
        # HAS a count, which shows the indexer is recording. All-null decides nothing.
        cnt = lambda h: h[3]["x_use"].get("count") or 0
        if len(top) > 1 and all(h[3]["kind"] == "application.launch" and h[3].get("x_use") for h in top) \
                and any(h[3]["x_use"].get("count") is not None for h in top) \
                and len({h[3]["outcome"].lower() for h in top}) == 1:
            ranked = sorted(top, key=lambda h: -cnt(h))
            if cnt(ranked[0]) >= 5 * max(cnt(ranked[1]), 1):
                hits = ranked + hits[len(top):]
                use_decided = {h[3]["id"]: h[3]["x_use"] for h in top}
    shown = hits[:limit]
    rows = [{"id": r["id"], "kind": r["kind"], "outcome": r["outcome"], "authority": r["authority"],
             "probe": r["x_probe_kind"], "tier": s, "label": r.get("x_label"),
             "latency": r.get("x_latency"), "latency_ms": r.get("x_latency_ms"),
             "irreversible": r.get("x_irreversible"), "undo": r.get("x_undo"),
             **({"args": a} if a else {})} for s, _, _, r, a in shown]
    # Zil ASK v2: how clear is the winner? Tiers are ranks, not probabilities, so say
    # exactly that: the top tier, the next DIFFERENT tier, the gap, and whether the top
    # tier holds one record (a unique top) — Zil decides local path vs agent from this.
    tiers = [h[0] for h in hits]
    nxt = next((t for t in tiers if t != tiers[0]), None) if tiers else None
    match = {"top_tier": tiers[0] if tiers else None, "next_tier": nxt,
             "margin": round(nxt - tiers[0], 3) if nxt is not None else None,
             "top_count": tiers.count(tiers[0]) if tiers else 0,
             "unique": bool(tiers) and tiers.count(tiers[0]) == 1}
    if use_decided and not match["unique"] and tiers.count(tiers[0]) == len(use_decided):
        match.update(unique=True, decided_by="use", use=use_decided)
    if question and tiers and not match["unique"]:
        # a QUESTION between a read and its setter ("what's the brightness"): the one read answers it
        reads = [h for h in hits if h[0] == tiers[0] and h[3]["kind"] == "system.state"]
        if len(reads) == 1 and reads[0] is hits[0]:
            match.update(unique=True, decided_by="question")
    if question and hits and hits[0][3]["kind"] != "system.state" and match["unique"]:
        # a QUESTION wants an answer; a page or an action is not one ("what's playing" matched the
        # CDs & DVDs page). Never let a question auto-run something that does not read.
        match.update(unique=False, question_without_read=True)
    if navigate and tiers and not match["unique"]:
        # "go to X" / "open X": the one top-tier PAGE (or app) is the navigation
        pref = "application.launch" if want_app else "system.pane"
        nav = [h for h in hits if h[0] == tiers[0] and h[3]["kind"] == pref] or \
              [h for h in hits if h[0] == tiers[0] and h[3]["kind"] in ("system.pane", "application.launch")]
        # a page's own sub-anchor ("Focus › Focus") is the same place: the parent stands for both
        nav = [h for h in nav if not any(h[3]["id"].startswith(o[3]["id"] + ".") for o in nav)]
        if len(nav) == 1 and nav[0] is hits[0]:
            match.update(unique=True, decided_by="navigate")
    if hits and rows:
        # The other outcome a person may have meant ("go to do not disturb": open Focus,
        # or turn it on). Prefer a record that can ACT on the subject (takes on/off),
        # suggested with "on"; else a read ranked close to the top.
        surface = lambda r: "page" if r["kind"] in ("system.pane", "application.launch") else "act"
        cands = [h for h in hits[1:] if surface(h[3]) != surface(hits[0][3]) and h[3]["kind"] != "system.intent"]
        actor = next((h for h in cands if h[0] <= tiers[0] + 0.5 and record_args(h[3], None, ("on", ["on"]))), None) \
            if surface(hits[0][3]) == "page" else None
        other = actor or next((h for h in cands if h[0] <= tiers[0] + 0.5), None)
        if other:
            sug = record_args(other[3], None, ("on", ["on"])) if other is actor else {}
            match["also"] = {"id": other[3]["id"], "label": other[3].get("x_label"), "kind": other[3]["kind"],
                             **({"args": sug, "args_suggested": True} if sug else {})}
    if trailing and tiers and tiers[0] == 0:
        took = [h for h in hits if h[0] == 0 and h[4]]
        if len(took) == 1 and took[0] is hits[0]:
            match.update(unique=True, decided_by="value")
    if cue and tiers and not match["unique"]:
        # the WORDS decide a tie: exactly one top-tier record took the spoken value
        took = [h for h in hits if h[0] == tiers[0] and len(h[4]) - ("host" in h[4]) > 0]
        if len(took) == 1 and took[0] is hits[0]:
            match.update(unique=True, decided_by="value")
    recall = None
    if not hits and not host and RECALL_ON:
        recall = recall_query(" ".join(raw), CRITERIA_TOP if chooser else RECALL_TOP)
    byid = {r["id"]: r for r in idx["records"]} if recall and recall.get("results") else {}
    recall_recs = [byid[i] for _, i in (recall or {}).get("results", []) if i in byid]
    if recall and recall.get("results") and not recall_recs:
        # vector hits whose ids are not in this index must never read as "no results" (daystra's trap, #hilt 375)
        recall = {"unavailable": "recall vectors name ids this index does not hold (stale vectors); rebuild"}
    if "--criteria" in OPTS:
        emit_criteria(q, [h[3] for h in hits[:CRITERIA_TOP]] or recall_recs,
                      {"recall": recall} if recall else None)
    if not hits and host:
        emit({"query": q, "verdict": "NONE", "results": [], "total": 0, "heard": {"host": host_words},
              "why": "host-unreachable-by-kind"},
             f"NONE '{q}' on {host['name']}: nothing that matches can run on another Mac. Only the "
             "status reads, thermals and resources reach the fleet (typed_by tailnet.mac).", 0)
    if not hits and recall_recs:
        # by meaning, not by words: candidates for a chooser or a human, never unique
        sc = {i: s_ for s_, i in recall["results"]}
        rrows = [{"id": r["id"], "kind": r["kind"], "outcome": r["outcome"], "authority": r["authority"],
                  "probe": r["x_probe_kind"], "tier": None, "recall_score": sc[r["id"]], "label": r.get("x_label"),
                  "latency": r.get("x_latency"), "latency_ms": r.get("x_latency_ms"),
                  "irreversible": r.get("x_irreversible"), "undo": r.get("x_undo")} for r in recall_recs]
        lines = [f"{len(rrows)} by meaning for '{q}' (no word matched; {recall['model']} via {recall['url']}, "
                 f"{recall['ms']} ms — candidates, not a decision)"]
        lines += [f"  {x['id']:<58} {x['recall_score']:.2f}  {x['outcome'][:70]}" for x in rrows]
        emit({"verdict": "FOUND", "query": q, "total": len(rrows), "results": rrows,
              "match": {"top_tier": None, "next_tier": None, "margin": None, "top_count": len(rrows),
                        "unique": False, "decided_by": "recall"},
              "recall": {k: v for k, v in recall.items() if k != "results"}}, "\n".join(lines))
    if not hits:
        why_r = (recall or {}).get("unavailable") or ((f"nothing scored above {RECALL_MIN} by meaning (best "
                                                      f"{recall.get('best_below_floor')})") if recall else None)
        emit({"query": q, "verdict": "NONE", "results": [], "total": 0,
              **({"recall": {k: v for k, v in recall.items() if k != "results"}} if recall else {})},
             f"NONE nothing in the index matches '{q}' (searched {len(idx['records'])} records; "
             f"`hilt orient` lists the holes — absence here is not absence from the Mac)"
             + (f"; recall: {why_r}" if why_r else ""), 0)
    lines = [f"{len(hits)} match(es) for '{q}'" + (f", showing {len(shown)} (--all for every one)"
                                                   if len(hits) > len(shown) else "")]
    for x in rows:
        lines.append(f"  {x['id']:<58} {x['kind']:<19} {x['authority']:<15} probe:{x['probe']:<22} {x['outcome'][:70]}")
    heard = {k: v for k, v in (("host", host_words), ("value", " ".join(value_words or []) or None),
                               ("level", " ".join(level_words or []) or None),
                               ("device", " ".join(device_words or []) or None),
                               ("trailing", " ".join(trailing or []) or None)) if v}
    if heard:
        lines.append("  args from the words: " + ", ".join(f"{k} <- '{v}'" for k, v in heard.items())
                     + (f" -> {rows[0]['id']} {rows[0].get('args')}" if rows and rows[0].get("args") else ""))
    emit({"verdict": "FOUND", "query": q, "total": len(hits), "results": rows, "match": match,
          **({"heard": heard} if heard else {})}, "\n".join(lines))


def cmd_describe(args):
    if not args:
        die(2, "REFUSED describe needs an id from `hilt find`")
    idx = load()
    rid = args[0]
    rec = next((r for r in idx["records"] if r["id"] == rid), None)
    if not rec:
        low = rid.lower()
        near = [r["id"] for r in idx["records"] if low in r["id"].lower()][:5]
        die(2, f"UNKNOWN {rid} is not an id in the index." +
            (f" Did you mean: {', '.join(near)}" if near else " Try `hilt find <words>`."),
            {"verdict": "UNKNOWN", "id": rid, "suggest": near})
    lines = [f"{rec['id']}  [{rec['kind']}]", f"  safety    {'IRREVERSIBLE' if rec.get('x_irreversible') else 'reversible'}"
             + (" · CONFIRM REQUIRED (run refuses with a 60 s token; replay with --confirm=<token>)" if rec.get("x_confirm") else "")
             + f" — undo: {rec.get('x_undo')}", f"  label     {rec.get('x_label')}  · latency {rec.get('x_latency')} "
             f"({rec.get('x_latency_ms')} ms, {rec.get('x_latency_source')})", f"  outcome   {rec['outcome']}"
             + (f"\n  situation {rec['x_situation']}" if rec.get("x_situation") else ""),
             f"  provider  {rec['provider']}", f"  authority {rec['authority']}"
             + (f" ({rec['x_authority_confidence']})" if rec.get("x_authority_confidence") else ""),
             f"  probe     {rec['x_probe_kind']}" + (f": {rec['probe']}" if rec.get("probe") else "")]
    if rec.get("x_reload"):
        lines.append(f"  reload    {rec['x_reload']}  (effect {rec.get('x_effect')})")
    for p in rec.get("x_params") or []:
        extra = ""
        if p.get("enum"):
            extra = " one of " + "|".join(map(str, p["enum"]))
        elif p.get("dynamic_options"):
            extra = " (options resolved at run time by the provider)"
        if p.get("range"):
            extra += f" range {p['range']}"
        if p.get("type") == "path":
            extra += f" must {'+'.join(p.get('must') or []) or 'nothing'}, under {' or '.join(p.get('roots') or ['~'])}"
        lines.append(f"  param     {p['name']}: {p['type']}{' (optional)' if p.get('optional') else ''}{extra}")
    if rec.get("x_note"):
        lines.append(f"  note      {rec['x_note']}")
    lines.append(f"  source    {', '.join(rec.get('x_source', []))}")
    emit(dict({k: v for k, v in rec.items() if not k.startswith("_")}, verdict="DESCRIBED"), "\n".join(lines))


def cmd_owners(args):
    if not args:
        die(2, "REFUSED owners needs a preference domain or plist path")
    idx = load()
    raw = os.path.expanduser(args[0])
    scope = "user"
    if "/" in raw:
        p = os.path.abspath(raw)
        if os.path.isdir(p):
            die(2, f"REFUSED {p} is a directory. Ownership is per preference domain; ask about "
                   "one plist or one domain.", {"verdict": "REFUSED", "target": p})
        if not p.endswith(".plist"):
            die(2, f"REFUSED hilt answers ownership for preference domains and their plists; "
                   f"{p} is neither. (Omarchy config files are sheath's question.)",
                {"verdict": "REFUSED", "target": p})
        base = os.path.basename(p)[:-6]
        base = re.sub(r"\.[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$", "", base)
        if p.startswith(PREFS_SYSTEM + "/"):
            scope = "system"
        if not os.path.exists(p):
            die(3, f"VACUOUS {p} does not exist — nothing was checked. Fix the path and ask again.",
                {"verdict": "VACUOUS", "target": p})
        dom = base
    else:
        dom = raw
    if dom in GLOBAL_DOMAINS:
        emit({"verdict": "CONTESTED", "domain": "NSGlobalDomain", "writers": "any app, via cfprefsd",
              "point_owner": "System Settings"},
             "CONTESTED NSGlobalDomain — every app may write it through cfprefsd; System Settings "
             "is the point owner. Write it with `defaults write -g`, never by editing the plist.")
    d = idx["domains"].get(dom)
    plist = os.path.join(PREFS_USER if scope == "user" else PREFS_SYSTEM, dom + ".plist")
    if d is None and not os.path.exists(plist):
        die(3, f"VACUOUS {dom} is not a defaults domain on this box and has no plist — nothing "
               "was checked. Fix the name and ask again.", {"verdict": "VACUOUS", "domain": dom})
    if idx["spotlight"] != "enabled":
        die(4, f"UNVERIFIABLE {dom} exists, but Spotlight is {idx['spotlight']} so its owning "
               "bundle cannot be resolved. This is not UNOWNED.",
            {"verdict": "UNVERIFIABLE", "domain": dom, "why": "spotlight " + idx["spotlight"]})
    bundles = (d or {}).get("bundles")
    if bundles is None:  # domain seen only as a file, not in `defaults domains`
        rc, out, _ = sh(["mdfind", f"kMDItemCFBundleIdentifier == '{dom}'"], 20)
        bundles = [l for l in out.splitlines() if l.strip()]
    keys = None
    pl = read_plist(plist)
    if isinstance(pl, dict):
        keys = len(pl)
    base = {"domain": dom, "scope": scope, "plist": plist if os.path.exists(plist) else None,
            "keys": keys, "bundles": bundles,
            "rule": "write with `defaults`, never by editing the plist (cfprefsd caches it)"}
    tail = f"  plist {base['plist'] or '(none — held by cfprefsd only)'} · keys {keys if keys is not None else '?'}"
    if not bundles:
        emit(dict(base, verdict="UNOWNED"),
             f"UNOWNED {dom} — no bundle on this box claims this domain. That is common for "
             f"daemons and removed apps; it does NOT mean safe to edit.\n{tail}")
    if len(bundles) > 1:
        emit(dict(base, verdict="CONTESTED"),
             f"CONTESTED {dom} — {len(bundles)} bundles on this box share the id:\n"
             + "\n".join(f"  {b}" for b in bundles) + f"\n{tail}")
    emit(dict(base, verdict="OWNED"), f"OWNED {dom} by {bundles[0]}\n{tail}")


def cmd_traps(args):
    idx = load()
    t = idx["traps"]
    if args:
        t = [x for x in t if x["id"] == args[0]]
        if not t:
            die(2, f"UNKNOWN trap {args[0]}", {"verdict": "UNKNOWN", "trap": args[0]})
    lines = []
    for x in t:
        lines += [f"{x['id']}: {x['trap']}", f"  rule      {x['rule']}", f"  falsifier {x['falsifier']}"]
    emit({"verdict": "OK", "traps": t}, "\n".join(lines) or "no traps")


# ---------------------------------------------------------------- permissions (TCC, read-only)
# The privacy database is LIVE state, read at call time (like a run query), and
# NEVER written by hilt (trap tcc-db-owned-by-tccd): the system db is root's,
# and the user db, though writable by any process with Full Disk Access, is
# tccd's live store. Apple's supported grants are a human in Settings or an MDM
# PPPC profile. hilt's job is the diagnosis and the exact pane to fix it in.
# Connections are opened `mode=ro`, so no statement here can write.

def user_tcc_db():
    """The per-user TCC database. Through macOS 26 it is
    ~/Library/Application Support/com.apple.TCC/TCC.db. macOS 27 (26A428, measured
    2026-10-06 with lsof on the user tccd) moved it into a ProtectedSystem data
    container: /private/var/containers/Data/ProtectedSystem/<uuid>/Data/Library/
    Application Support/com.apple.TCC/TCC.db — and the old directory no longer exists,
    so every host read "unreadable" after the update, Full Disk Access or not. The
    legacy path wins when present; else the container path; else the legacy path
    (so the error names a real location)."""
    env = os.environ.get("HILT_TCC_USER")
    if env:
        return env
    legacy = os.path.expanduser("~/Library/Application Support/com.apple.TCC/TCC.db")
    if os.path.exists(legacy):
        return legacy
    cands = sorted(glob.glob("/private/var/containers/Data/ProtectedSystem/*/Data/Library/Application Support/com.apple.TCC/TCC.db"))
    if cands:
        return cands[0] if len(cands) == 1 else max(cands, key=os.path.getmtime)
    # The container is not enumerable without Full Disk Access; the user's own tccd holds
    # the file open, and lsof names it (measured 2026-10-06: tccd 938, markstatkus).
    try:
        pids = [l.split()[0] for l in subprocess.run(["pgrep", "-u", str(os.getuid()), "-x", "tccd"], capture_output=True, text=True, timeout=5).stdout.split()]
        for pid in pids:
            out = subprocess.run(["lsof", "-p", pid, "-Fn"], capture_output=True, text=True, timeout=10).stdout
            for line in out.splitlines():
                if line.startswith("n") and line.endswith("/com.apple.TCC/TCC.db"):
                    return line[1:]
    except (OSError, subprocess.SubprocessError):
        pass
    return legacy


TCC_DBS = [("user", user_tcc_db()),
           ("system", os.environ.get("HILT_TCC_SYSTEM") or "/Library/Application Support/com.apple.TCC/TCC.db")]
# auth_value as TCC stores it. 0-3 are the long-observed meanings; anything
# else is printed raw rather than guessed.
TCC_AUTH = {0: "denied", 1: "unknown", 2: "allowed", 3: "limited"}
FOLDER_SERVICES = ("kTCCServiceSystemPolicyDesktopFolder", "kTCCServiceSystemPolicyDocumentsFolder",
                   "kTCCServiceSystemPolicyDownloadsFolder", "kTCCServiceSystemPolicyNetworkVolumes",
                   "kTCCServiceSystemPolicyRemovableVolumes")


def tcc_read():
    """(rows, unreadable). A db that cannot be opened is reported by scope,
    never read as 'no grants'."""
    rows, bad = [], []
    for scope, path in TCC_DBS:
        try:
            con = sqlite3.connect(f"file:{path}?mode=ro", uri=True, timeout=2)
            cur = con.execute("select service, client, client_type, auth_value, auth_reason, "
                              "last_modified, indirect_object_identifier from access")
            for svc, client, ctype, av, reason, mod, target in cur.fetchall():
                rows.append({"db": scope, "service": svc, "client": client,
                             "client_type": "bundle" if ctype == 0 else "path",
                             "auth_value": av, "state": TCC_AUTH.get(av, f"value {av} (undocumented)"),
                             "auth_reason": reason,
                             "last_modified": time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(mod)) if mod else None,
                             "target": target if target and target != "UNUSED" else None})
            con.close()
        except sqlite3.Error as e:
            bad.append({"db": scope, "path": path, "error": str(e)})
    return rows, bad


def tcc_decorate(row, tmap):
    m = tmap.get(row["service"]) or {}
    row["service_name"] = m.get("name") or row["service"]
    row["fix"] = m.get("pane")
    return row


def resolve_client(idx, q, rows):
    """An app name, bundle id or binary path -> the TCC client id(s) it means."""
    clients = {r["client"] for r in rows}
    if q in clients:
        return [q]
    ql, qn = q.lower(), norm(q)
    hits = []
    for r in idx["records"]:
        if r["kind"] != "application.launch":
            continue
        names = [r["x_bundle"].lower()] + r.get("x_aliases", [])
        if ql in names or qn in (norm(n) for n in names):
            hits.append(r["x_bundle"])
    if not hits:  # a prefix of the app name ("iterm" -> iTerm2)
        hits = [r["x_bundle"] for r in idx["records"] if r["kind"] == "application.launch"
                and any(norm(a).startswith(qn) for a in r.get("x_aliases", []) if not a.startswith(("open ", "launch ")))]
    ci = {c.lower(): c for c in clients}
    return sorted({ci.get(h.lower(), h) for h in hits})


def cmd_permissions(args):
    obj, text, code = permissions_answer(load(), args)
    emit(obj, text, code)


def permissions_answer(idx, args):
    """(json, text, exit). Shared by the verb and by `run state.permissions`."""
    tmap = idx.get("tcc_services") or {}
    rows, bad = tcc_read()
    if len(bad) == len(TCC_DBS):
        return ({"verdict": "UNVERIFIABLE", "why": "tcc-unreadable", "unreadable": bad,
                 "fix": "system.pane.privacysecurity.allfiles"}, "UNVERIFIABLE the privacy database is unreadable from this process "
               f"({bad[0]['error']}). TCC.db needs Full Disk Access for the app hilt runs "
               "under (the terminal, or the host that spawned the MCP door) — this is not "
               "'no permissions'. Grant it: hilt run system.pane.privacysecurity.allfiles", 4)
    rows = [tcc_decorate(r, tmap) for r in rows]
    order = {"denied": 0, "limited": 1, "unknown": 2, "allowed": 3}
    rows.sort(key=lambda r: (order.get(r["state"], 1), r["client"], r["service_name"]))
    partial = f"  (PARTIAL: {', '.join(b['db'] for b in bad)} db unreadable)" if bad else ""
    if not args:
        denied = [r for r in rows if r["state"] != "allowed"]
        lines = [f"{len(denied)} non-allowed decision(s) across {len({r['client'] for r in rows})} "
                 f"clients ({len(rows)} rows){partial}"]
        for r in denied:
            lines.append(f"  {r['state']:<9} {r['client'][:42]:<42} {r['service_name'][:40]:<40} "
                         f"{r['last_modified'] or ''}  fix: {r['fix'] or '(no Settings anchor)'}")
        return ({"verdict": "OK", "rows": denied, "total_rows": len(rows), "unreadable": bad},
                "\n".join(lines), 0)
    q = " ".join(args)
    targets = resolve_client(idx, q, rows)
    if not targets:
        return ({"verdict": "VACUOUS", "query": q},
                f"VACUOUS '{q}' is not an app, bundle id or TCC client on this Mac — nothing was "
                "checked. Try `hilt find <app name>`.", 3)
    mine = [r for r in rows if r["client"] in targets]
    hints = []
    have = {r["service"]: r["state"] for r in mine}
    if have.get("kTCCServiceSystemPolicyAllFiles") != "allowed" and any(s in have for s in FOLDER_SERVICES):
        hints.append("Full Disk Access is " + have.get("kTCCServiceSystemPolicyAllFiles", "not decided")
                     + ", so this app is asked folder by folder (Desktop, Documents, Downloads, network "
                       "and removable volumes). Allowing Full Disk Access ends those prompts: "
                       "hilt run system.pane.privacysecurity.allfiles")
    for r in mine:
        if r["state"] == "denied" and r["fix"] and not (hints and r["service"] == "kTCCServiceSystemPolicyAllFiles"):
            hints.append(f"{r['service_name']} was DENIED {r['last_modified'] or ''}: a denial is "
                         f"remembered and not re-asked; the app fails silently. Fix: hilt run {r['fix']}")
    if not mine:
        return ({"verdict": "NONE", "clients": targets, "rows": [], "unreadable": bad},
                f"NONE {', '.join(targets)}: no privacy decision recorded — its next protected access "
                f"will prompt.{partial}", 0)
    lines = [f"{', '.join(targets)}: {len(mine)} decision(s){partial}"]
    for r in mine:
        lines.append(f"  {r['state']:<9} {r['service_name'][:44]:<44} {r['db']:<6} {r['last_modified'] or '':<19}"
                     + (f"  → {r['target']}" if r["target"] else "")
                     + (f"  fix: {r['fix']}" if r["state"] != "allowed" and r["fix"] else ""))
    lines += [f"  hint: {h}" for h in hints]
    return ({"verdict": "OK", "clients": targets, "rows": mine, "hints": hints, "unreadable": bad},
            "\n".join(lines), 0)


# ---------------------------------------------------------------- run (CUT C)
# Every actuator is an argv list built from the RECORD plus args validated
# against the record's typed params. No shell, no string built from user text,
# no osascript. Probes follow probe_kind() — the same ladder find/describe print.

RUN_EXIT = {"verified": 0, "query": 0, "failed": 1, "refused": 2, "unverifiable": 4, "mismatched": 5}
POLL_SECONDS = 10.0
WRITE_FLAG = {"boolean": "-bool", "integer": "-int", "float": "-float", "string": "-string",
              "path": "-string"}


class Refusal(Exception):
    def __init__(self, why, detail, **extra):
        super().__init__(detail)
        self.why, self.detail, self.extra = why, detail, extra


def typed_args(rec, args):
    """Positional args checked against the record's typed params. A param the
    index did not type — a string with no enum — is refused, never guessed."""
    params = rec.get("x_params") or []
    if len(args) > len(params):
        raise Refusal("bad-args", f"{rec['id']} takes at most {len(params)} argument(s), got "
                                  f"{len(args)}. `hilt describe {rec['id']}` lists them.")
    vals = []
    for i, p in enumerate(params):
        if i >= len(args) and p.get("default") is not None and p.get("optional"):
            vals.append((p["name"], str(p["default"])))  # an authored default, typed like a given value would be
            continue
        if i >= len(args) and p.get("default_from") == "primary":
            # the primary network service / device, resolved live (CUT H slice 3): "which dns am
            # i using" means the one carrying traffic, never a guess from a list
            v = primary_network(p.get("typed_by"))
            if v:
                vals.append((p["name"], v))
            continue
        if i >= len(args):
            if p.get("optional"):
                continue  # a later optional param may still carry a default (never break here: 2026-10-06)
            if all(q.get("optional") for q in params[i:]):
                break
            raise Refusal("bad-args", f"missing argument '{p['name']}' for {rec['id']}. "
                                      f"`hilt describe {rec['id']}` lists it.")
        a, enum, typ, rng = args[i], p.get("enum"), p.get("type"), p.get("range")
        if enum:
            if a not in [str(e) for e in enum]:
                raise Refusal("bad-enum", f"'{a}' is not one of {'|'.join(map(str, enum))} for "
                                          f"'{p['name']}'.")
        elif p.get("typed_by") == "tailnet.mac":
            resolve_peer(a)  # refuses before anything connects
        elif p.get("typed_by") == "bluetooth.paired":
            resolve_bt(a)  # refuses before anything acts
        elif p.get("typed_by") in ("audio.level", "display.level"):
            if not re.fullmatch(r"100|[1-9]?\d|up|down", a):
                raise Refusal("bad-enum", f"'{a}' is not a volume: 0..100, up or down.")
        elif (p.get("typed_by") or "").startswith("audio."):
            try:
                resolve_audio(p["typed_by"].split(".", 1)[1], a)  # refuses before anything acts
            except Refusal:
                if not (p["typed_by"] == "audio.output" and bt_audio_match(a)):
                    raise  # a paired Bluetooth headset is connected first, in run
        elif p.get("typed_by") == "diskutil.volume":
            a = resolve_volume(a, p.get("external_only"))  # the device identifier, refused before acting
        elif p.get("typed_by") == "net.host":
            if not NET_HOST.fullmatch(a) or ".." in a:
                raise Refusal("bad-type", f"'{a}' is not a hostname or IP address for '{p['name']}'.")
        elif p.get("typed_by") == "app.process":
            a = resolve_app_process(a)  # the app's executable name, from its own Info.plist
        elif p.get("typed_by") == "app.bundle":
            a = resolve_app_record(a)["x_bundle"]
        elif p.get("typed_by") == "app.path":
            rec_ = resolve_app_record(a)
            a = (rec_.get("x_paths") or [None])[0]
            if not a:
                raise Refusal("bad-enum", f"{rec_['x_bundle']} has no path in the index.")
        elif p.get("typed_by") == "text.subsystem":
            if not TEXT_SUBSYSTEM.fullmatch(a):
                raise Refusal("bad-type", f"'{a}' is not a subsystem name (reverse-DNS, e.g. com.apple.TimeMachine).")
        elif p.get("typed_by") == "text.token":
            if not TEXT_TOKEN.fullmatch(a):
                raise Refusal("bad-type", f"'{a}' is not a token for '{p['name']}' (letters, digits, . _ -; no spaces).")
        elif p.get("typed_by") == "simctl.device":
            a = resolve_sim(a)
        elif p.get("typed_by") == "defaults.domain":
            doms = load().get("domains") or {}
            hit = [x for x in doms if x.lower() == a.lower()]
            if not hit:
                raise Refusal("bad-enum", f"'{a}' is not a defaults domain the index derived ({len(doms)} known). `hilt owners {a}`.")
            a = hit[0]
        elif p.get("typed_by") == "launchd.label":
            a = resolve_launchd_label(a, p.get("user_agent_only"))
        elif p.get("typed_by") == "wifi.scanned":
            a = resolve_wifi(a)  # a network in range, by its scanned name
        elif p.get("typed_by") == "net.ip":
            if not (NET_IP4.fullmatch(a) or (":" in a and NET_IP6.fullmatch(a))):
                raise Refusal("bad-type", f"'{a}' is not an IPv4 or IPv6 address for '{p['name']}'.")
        elif p.get("typed_by") == "net.cidr":
            c = net_cidr(a)
            if not c:
                raise Refusal("bad-type", f"'{a}' is not a network in CIDR form for '{p['name']}' (e.g. 192.168.1.0/24).")
            a = c
        elif p.get("typed_by") == "networksetup.service":
            a = resolve_ns_service(a)  # the service's exact name, from networksetup's own list
        elif p.get("typed_by") == "networksetup.device":
            if a not in ns_devices():
                raise Refusal("bad-enum", f"'{a}' is not a network device here. Devices: " + ", ".join(ns_devices()))
        elif p.get("typed_by") == "text.filename":
            if not TEXT_FILENAME.fullmatch(a):
                raise Refusal("bad-type", f"'{a}' is not a file name for '{p['name']}' (letters, digits, . _ - and spaces; no slashes).")
        elif p.get("typed_by") == "app.running":
            a = str(resolve_running_app(a))  # the pid; refused before anything acts
        elif p.get("typed_by") == "tz.zoneinfo":
            if not re.fullmatch(r"[A-Za-z0-9_+-]+(/[A-Za-z0-9_+-]+){0,2}", a) or not os.path.isfile("/usr/share/zoneinfo/" + a):
                raise Refusal("bad-enum", f"'{a}' is not a zone in /usr/share/zoneinfo (e.g. America/Los_Angeles).")
        elif p.get("typed_by") == "application.launch":
            apps = [r for r in load()["records"] if r["kind"] == "application.launch"]
            names = {n for r in apps for n in [r["x_bundle"].lower()] + r.get("x_aliases", [])}
            if a.lower() not in names and norm(a) not in {norm(n) for n in names}:
                raise Refusal("bad-enum", f"'{a}' is not an app in the index (name or bundle id) for "
                                          f"'{p['name']}'. `hilt find {a}`.")
        elif typ == "path":
            a = check_path(p, a)
        elif typ in ("integer", "float"):
            pat = r"-?\d+" if typ == "integer" else r"-?\d+(\.\d+)?"
            if not re.fullmatch(pat, a):
                raise Refusal("bad-type", f"'{a}' is not a {typ} for '{p['name']}'.")
            if rng and not (rng[0] <= float(a) <= rng[1]):
                raise Refusal("out-of-range", f"{a} is outside {rng[0]}..{rng[1]} for '{p['name']}'.")
        else:
            raise Refusal("untyped-param", f"'{p['name']}' is a {typ or 'value'} the index did not "
                                           "type (no enum, no numeric range, no path rules), so run "
                                           "will not pass "
                                           "text through to it. Refused rather than guessed.")
        vals.append((p["name"], a))
    return vals


def poll(read, done, seconds):
    end = time.time() + seconds
    while True:
        state = read()
        if done(state) or time.time() >= end:
            return state
        time.sleep(0.25)


def pids(name):
    rc, out, _ = sh(["pgrep", "-x", name], 5)
    return sorted(int(x) for x in out.split()) if rc == 0 else []


def app_pid(bid):
    rc, out, _ = sh(["lsappinfo", "info", "-only", "pid", "-app", bid], 5)
    # macOS 26 printed `"pid"=123`; macOS 27 (26A428) prints `pid = 123` in a block whose
    # bundleID reads NULL. Both forms; an app that is not running prints nothing.
    m = re.search(r'"?\bpid"?\s*=\s*(\d+)', out)
    return int(m.group(1)) if m else None


def reload_argv(rec):
    """x_reload is index text; only `killall <ProcessName>` is honoured."""
    r = rec.get("x_reload")
    if not r:
        return None
    argv = shlex.split(r)
    if len(argv) != 2 or argv[0] != "killall" or not re.fullmatch(r"[A-Za-z][A-Za-z0-9._-]*", argv[1]):
        raise Refusal("bad-record", f"{rec['id']} carries reload '{r}', which is not `killall "
                                    "<process>`; run executes no other reload shape.")
    return argv


def same_value(typ, got, want):
    if got is None:
        return False
    if typ == "boolean":
        return got == ("1" if want == "true" else "0")
    if typ == "integer":
        try:
            return float(got) == float(want)
        except ValueError:
            return False
    if typ == "float":
        # a plist <real> may be float32: 0.001 is stored as 0.0010000000474974513 and
        # `defaults read` prints 0.001 (measured 2026-10-10, system.windows.resize-time);
        # equal at float32 precision is equal
        try:
            g, w = float(got), float(want)
        except ValueError:
            return False
        return abs(g - w) <= 1e-6 * max(1.0, abs(g), abs(w))
    if typ == "path":
        # defaults stores the string verbatim (trailing slash kept, /tmp left
        # unresolved), so a raw compare would call a correct write a no-op.
        return resolve_path(got) == resolve_path(want)
    return got == want


def run_setting(rec, vals, no_reload):
    want = vals[0][1]
    typ = rec["x_params"][0]["type"]
    dflag = "-g" if rec["x_domain"] in GLOBAL_DOMAINS else rec["x_domain"]
    rl = reload_argv(rec)
    owner = rl[1] if rl else None

    def read():
        rc, out, _ = sh(["defaults", "read", dflag, rec["x_key"]], 10)
        return {"value": out.strip() if rc == 0 else None,
                "owner": owner, "owner_pids": pids(owner) if owner else None}

    before = read()
    already = same_value(typ, before["value"], want)
    # LIVE path first: `killall Dock` pulls other apps' windows forward (Google
    # Messages, Mark 2026-09-28, "hide the dock" by voice). System Events' dock
    # preferences are applied BY the running Dock, no restart. Only when the host
    # already holds Automation → System Events: never raise a prompt to avoid one.
    prop = rec.get("x_live_sysevents")
    if prop and rl and not no_reload and not already and re.fullmatch(r"[a-z]+", want):
        app = responsible_app()
        if app and tcc_state(app, "kTCCServiceAppleEvents", "com.apple.systemevents") == "allowed":
            rc, _, err = sh(["osascript", "-e", f'tell application "System Events" to set {prop} of '
                             f'dock preferences to {want}'], 10)
            if rc == 0:
                after = poll(read, lambda s: same_value(typ, s["value"], want), POLL_SECONDS)
                extra = {"already": False, "reloaded": False, "live_via": "System Events dock preferences",
                         "effect": "live, no Dock restart"}
                if not same_value(typ, after["value"], want):
                    return "mismatched", before, after, (f"System Events set {prop} but the readback is "
                                                         f"{after['value']!r}, not {want!r}"), extra
                same = before["owner_pids"] == after["owner_pids"]
                return "verified", before, after, (f"readback {before['value']!r} -> {after['value']!r}; applied "
                                                   f"live by the Dock (pid {after['owner_pids']}"
                                                   f"{', unchanged' if same else ', CHANGED'}), no restart"), extra
    rc, _, err = sh(["defaults", "write", dflag, rec["x_key"], WRITE_FLAG[typ], want], 10)
    if rc != 0:
        return "failed", before, None, f"defaults write exited {rc}: {err.strip()[:200]}", {}
    reloaded = False
    if rl and not no_reload:
        sh(rl, 10)  # exits 1 when the owner is not running; it reads the value at its next launch
        reloaded = True

    def live(s):
        if not owner or not before["owner_pids"]:
            return True  # nothing running holds the old value
        return bool(s["owner_pids"]) and not set(s["owner_pids"]) & set(before["owner_pids"])

    ok = lambda s: same_value(typ, s["value"], want) and live(s)
    after = poll(read, ok, POLL_SECONDS if reloaded else 0)
    extra = {"already": already, "reloaded": reloaded, "effect": rec.get("x_effect")}
    if not same_value(typ, after["value"], want):
        return "mismatched", before, after, (f"defaults write exited 0 but the readback is "
                                             f"{after['value']!r}, not {want!r}"), extra
    if not live(after):
        if already:
            return "verified", before, after, f"already {want}; {owner} holds it", extra
        why = ("reload suppressed" if no_reload else f"{owner} did not restart within {POLL_SECONDS:g}s")
        return "mismatched", before, after, (f"written ({before['value']!r} -> {after['value']!r}) but "
                                             f"{owner} has not reloaded ({why}): the change is not "
                                             "live. See `hilt traps owner-must-reload`."), extra
    note = f"readback {before['value']!r} -> {after['value']!r}"
    if owner and before["owner_pids"]:
        note += f"; {owner} reloaded (pid {before['owner_pids']} -> {after['owner_pids']})"
    if not rl and rec.get("x_effect"):
        note += f"; takes effect {rec['x_effect']}"
    return "verified", before, after, note, extra


def run_launch(rec):
    bid = rec["x_bundle"]
    before = {"pid": app_pid(bid)}
    rc, _, err = sh(["open", "-b", bid], 30)
    if rc != 0:
        return "failed", before, None, f"open -b exited {rc}: {err.strip()[:200]}", {}
    # open returns before the app has a pid (trap open-returns-early): poll.
    after = poll(lambda: {"pid": app_pid(bid)}, lambda s: s["pid"] is not None, POLL_SECONDS)
    extra = {"already": before["pid"] is not None}
    if after["pid"] is None:
        return "mismatched", before, after, (f"open -b exited 0 but {bid} has no pid after "
                                             f"{POLL_SECONDS:g}s"), extra
    return "verified", before, after, f"{bid} running, pid {after['pid']}" + (
        " (already running)" if extra["already"] else ""), extra


def run_query(rec, vals):
    rc, out, err = sh(rec["x_argv"] + [v for _, v in vals], 60)
    after = {"output": out}
    if rc != 0:
        return "failed", None, after, f"{rec['x_argv'][0]} exited {rc}: {(err or out).strip()[:200]}", {}
    return "query", None, after, out.rstrip(), {}


def tcp_listening():
    rc, out, _ = sh(["netstat", "-anp", "tcp"], 10)
    if rc != 0:
        return None
    ports = set()
    for line in out.splitlines():
        f = line.split()
        if len(f) >= 6 and f[-1] == "LISTEN":
            m = re.search(r"[.:](\d+)$", f[3])
            if m:
                ports.add(int(m.group(1)))
    return ports


def run_witness(rec):
    seen, listening = [], None
    for w in rec["x_witness"]:
        if "launchd" in w:
            rc, _, _ = sh(["launchctl", "print", w["launchd"]], 10)
            st = "on" if rc == 0 else ("off" if rc == 113 else "unknown")
            seen.append({"witness": f"launchd {w['launchd']}", "says": st,
                         "evidence": {0: "loaded", 113: "not loaded"}.get(rc, f"launchctl exited {rc}")})
        elif "listen_tcp" in w:
            if listening is None:
                listening = tcp_listening()
            p = w["listen_tcp"]
            st = "unknown" if listening is None else ("on" if p in listening else "off")
            seen.append({"witness": f"tcp {p}", "says": st,
                         "evidence": "netstat failed" if listening is None else
                         ("listening" if st == "on" else "not listening")})
        elif "argv" in w:
            rc, out, err = sh(w["argv"], 15)
            txt = (out + err).strip()
            on = re.search(w["on"], txt, re.M | re.I)
            off = None if on else re.search(w["off"], txt, re.M | re.I)
            st = "on" if on else ("off" if off else "unknown")
            m = on or off
            line = txt[txt.rfind("\n", 0, m.start()) + 1:].split("\n", 1)[0].strip() if m else \
                f"exit {rc}, no on/off line matched"
            seen.append({"witness": " ".join(os.path.basename(a) if i == 0 else a
                                             for i, a in enumerate(w["argv"])),
                         "says": st, "evidence": line[:160]})
    says = {x["says"] for x in seen} - {"unknown"}
    state = says.pop() if len(says) == 1 else ("disagree" if says else "unknown")
    detail = f"{state} — " + "; ".join(f"{x['witness']}: {x['evidence']}" for x in seen)
    if rec.get("x_fix"):
        detail += f". Change it (admin, human): hilt run {rec['x_fix']}"
    return "query", None, {"state": state, "witnesses": seen, "fix": rec.get("x_fix")}, detail, {"state": state}


def run_audio_set(direction, arg):
    connected = None
    try:
        want = resolve_audio(direction, arg)
    except Refusal:
        name = bt_audio_match(arg) if direction == "output" else None
        if not name:
            raise
        # "switch output to airpods" while they are paired but not connected: connect, then switch
        v, *_ = run_bt("connect", name, "--allow-prompt" in OPTS)
        if v != "verified":
            return "failed", None, None, f"{name} is paired but did not connect ({v}); nothing was switched", {}
        connected = name
        poll(lambda: next((d for d in audio_devices() or [] if d["output"] and norm(name) in norm(d["name"])), None),
             lambda d: d is not None, 8)
        want = resolve_audio(direction, name)
    flag = "default_" + direction
    cur = lambda: next((d for d in (audio_devices() or []) if d[flag]), None)
    before = cur()
    already = bool(before and before["id"] == want["id"])
    st = coreaudio()["set_default"](AUDIO_SEL[direction], want["id"])
    if st != 0:
        return "failed", {"device": before and before["name"]}, None, \
            f"AudioObjectSetPropertyData returned OSStatus {st}", {}
    after = poll(cur, lambda d: bool(d and d["id"] == want["id"]), 2)
    b, a = {"device": before and before["name"]}, {"device": after and after["name"]}
    if not after or after["id"] != want["id"]:
        return "mismatched", b, a, (f"set returned 0 but the default {direction} reads back as "
                                    f"{a['device']!r}, not {want['name']!r}"), {"already": already}
    a["speak"] = f"Sound {'plays through' if direction == 'output' else 'comes from'} {a['device']}."
    return "verified", b, a, ((f"connected {connected}; " if connected else "") + f"default {direction}: {b['device']!r} -> "
                              f"{a['device']!r}" + (" (already)" if already else "")), {"already": already, "connected_first": connected}


def bt_audio_match(a):
    """The ONE paired Bluetooth headset/speaker a spoken fragment names ("airpods"), or None."""
    _, devs = bt_devices()
    key = norm(re.sub(r"^(my|the)\s+", "", a.strip(), flags=re.I))
    hit = sorted({d["name"] for d in devs or [] if not d.get("le_only") and len(key) >= 3 and key in norm(d["name"])
                  and d.get("kind") in ("Headphones", "Headset", "Speaker", "AudioVideo", None)})
    return hit[0] if len(hit) == 1 else None


def _ca_set(dev, sel, value, ctype):
    import ctypes
    at = ctypes.cdll.LoadLibrary("/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox")

    class Addr(ctypes.Structure):
        _fields_ = [("sel", ctypes.c_uint32), ("scope", ctypes.c_uint32), ("elem", ctypes.c_uint32)]
    v = ctype(value)
    return at.AudioHardwareServiceSetPropertyData(dev, ctypes.byref(Addr(_fcc(sel), _fcc("outp"), 0)), 0, None,
                                                  ctypes.sizeof(v), ctypes.byref(v))


def default_output():
    return next((d for d in (audio_devices() or []) if d["default_output"]), None)


def run_volume(level):
    """Output volume 0..100, or a step up/down (10), on the default output. Native
    AudioToolbox virtual main volume: the menu-bar slider's own number."""
    out = default_output()
    if not out:
        return "failed", None, None, "no default output device", {}
    vol, muted = audio_volume(out["id"])
    if vol is None:
        raise Refusal("not-settable", f"{out['name']} has no software volume (set it on the device itself).")
    cur = round(vol * 100)
    want = max(0, min(100, cur + 10)) if level == "up" else max(0, min(100, cur - 10)) if level == "down" else int(level)
    st = _ca_set(out["id"], "vmvc", want / 100.0, __import__("ctypes").c_float)
    if st != 0:
        return "failed", {"volume_percent": cur}, None, f"AudioHardwareServiceSetPropertyData returned {st}", {}
    after = poll(lambda: round((audio_volume(out["id"])[0] or 0) * 100), lambda v: abs(v - want) <= 1, 2)
    b, a = {"volume_percent": cur, "device": out["name"]}, {"volume_percent": after, "device": out["name"],
                                                               "muted": muted, "units": {"volume_percent": "%"}}
    if abs(after - want) > 1:
        return "mismatched", b, a, f"volume set to {want}% but reads back {after}%", {}
    a["speak"] = f"Volume is {after} percent" + (", but the output is muted." if muted else ".")
    return "verified", b, a, f"volume {cur}% -> {after}% on {out['name']}" + (" (muted)" if muted else ""), \
        {"already": cur == want}


def run_mute(state):
    out = default_output()
    if not out:
        return "failed", None, None, "no default output device", {}
    _, before = audio_volume(out["id"])
    if before is None:
        raise Refusal("not-settable", f"{out['name']} has no software mute.")
    want = state == "on"
    import ctypes
    st = _ca_set(out["id"], "mute", 1 if want else 0, ctypes.c_uint32)
    if st != 0:
        return "failed", {"muted": before}, None, f"mute set returned {st}", {}
    after = poll(lambda: audio_volume(out["id"])[1], lambda m: m == want, 2)
    b, a = {"muted": before, "device": out["name"]}, {"muted": after, "device": out["name"],
                                                     "speak": "Sound is muted." if after else "Sound is on.", "units": {}}
    if after != want:
        return "mismatched", b, a, f"mute set to {want} but reads back {after}", {}
    return "verified", b, a, f"{out['name']}: muted {before} -> {after}", {"already": before == want}


def wifi_device():
    rc, out, _ = sh(["networksetup", "-listallhardwareports"], 10)
    m = re.search(r"Hardware Port: Wi-Fi\nDevice: (\S+)", out)
    return m.group(1) if m else None


def run_wifi_power(state):
    dev = wifi_device()
    if not dev:
        raise Refusal("native-unavailable", "this Mac has no Wi-Fi hardware port.")
    read = lambda: (re.search(r": (On|Off)\s*$", sh(["networksetup", "-getairportpower", dev], 10)[1] or "") or [None, None])[1]
    before = read()
    rc, out, err = sh(["networksetup", "-setairportpower", dev, state], 20)
    if rc != 0 or "rror" in out:
        return "failed", {"power": before}, None, f"networksetup exited {rc}: {(err or out).strip()[:160]}", {}
    after = poll(read, lambda v: (v or "").lower() == state, 5)
    b, a = {"power": before}, {"power": after, "speak": f"Wi-Fi is {state}.", "units": {}}
    if (after or "").lower() != state:
        return "mismatched", b, a, f"Wi-Fi power reads {after}, not {state}", {}
    return "verified", b, a, f"Wi-Fi ({dev}) {before} -> {after}", {"already": (before or "").lower() == state}


def host_holds(service, target=None):
    app = responsible_app()
    return bool(app) and tcc_state(app, service, target) == "allowed"


def run_dark_mode(state):
    # Live through System Events (the running session applies it, no logout), and
    # only when the host already holds that Automation grant: never raise a prompt.
    if not host_holds("kTCCServiceAppleEvents", "com.apple.systemevents"):
        raise Refusal("permission-would-prompt", "switching appearance live needs the host app's Automation "
                      "grant for System Events (`hilt setup dev` raises it once).", fix="Privacy_Automation")
    read = lambda: "on" if sh(["defaults", "read", "-g", "AppleInterfaceStyle"], 5)[1].strip() == "Dark" else "off"
    before = read()
    rc, out, err = sh(["osascript", "-e", 'tell application "System Events" to tell appearance preferences to '
                       f'set dark mode to {"true" if state == "on" else "false"}'], 15)
    if rc != 0:
        return "failed", {"dark": before}, None, f"System Events: {(err or out).strip()[:160]}", {}
    after = poll(read, lambda v: v == state, 5)
    b, a = {"dark": before}, {"dark": after, "speak": f"Dark mode is {after}.", "units": {}}
    if after != state:
        return "mismatched", b, a, f"appearance reads dark={after}, not {state}", {}
    return "verified", b, a, f"dark mode {before} -> {after}", {"already": before == state}


SCREEN_LOCKED_JS = """ObjC.import("CoreGraphics"); var d = ObjC.deepUnwrap($.CGSessionCopyCurrentDictionary());
JSON.stringify({locked: !!(d && d.CGSSessionScreenIsLocked)});"""


def screen_locked():
    rc, out, _ = sh(["osascript", "-l", "JavaScript", "-e", SCREEN_LOCKED_JS], 5)
    try:
        return json.loads(out)["locked"]
    except (ValueError, KeyError):
        return None


def run_screen_lock():
    # Apple's own lock (⌃⌘Q), sent by System Events: needs the host's Accessibility and
    # Automation → System Events, checked first so nothing prompts. Undo is a person
    # unlocking; that is the point. Witness: the session's own locked flag.
    if not (host_holds("kTCCServiceAccessibility") and host_holds("kTCCServiceAppleEvents", "com.apple.systemevents")):
        raise Refusal("permission-would-prompt", "locking sends ⌃⌘Q through System Events: the host app needs "
                      "Accessibility and Automation → System Events (`hilt setup dev`).", fix="Privacy_Accessibility")
    if screen_locked():
        return "verified", {"locked": True}, {"locked": True}, "already locked", {"already": True}
    rc, out, err = sh(["osascript", "-e", 'tell application "System Events" to keystroke "q" using {control down, command down}'], 10)
    if rc != 0:
        return "failed", {"locked": False}, None, f"System Events: {(err or out).strip()[:160]}", {}
    after = poll(screen_locked, lambda v: v is True, 4)
    if after is not True:
        return "mismatched", {"locked": False}, {"locked": after}, "the lock keystroke was sent but the session is not locked", {}
    return "verified", {"locked": False}, {"locked": True, "speak": "The screen is locked.", "units": {}}, "screen locked", {}


def night_shift_state():
    """{'active': bool, 'enabled': bool} from CoreBrightness's CBBlueLightClient (PRIVATE,
    read-only, same class as the thermal read Mark approved). None when it will not load."""
    import ctypes, ctypes.util
    try:
        objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("objc"))
        ctypes.cdll.LoadLibrary("/System/Library/PrivateFrameworks/CoreBrightness.framework/CoreBrightness")
    except OSError:
        return None
    objc.objc_getClass.restype = ctypes.c_void_p
    objc.sel_registerName.restype = ctypes.c_void_p
    msg = objc.objc_msgSend
    cls = objc.objc_getClass(b"CBBlueLightClient")
    if not cls:
        return None
    msg.restype, msg.argtypes = ctypes.c_void_p, [ctypes.c_void_p, ctypes.c_void_p]
    o = msg(msg(cls, objc.sel_registerName(b"alloc")), objc.sel_registerName(b"init"))
    buf = (ctypes.c_ubyte * 64)()
    msg.restype, msg.argtypes = ctypes.c_bool, [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
    if not msg(o, objc.sel_registerName(b"getBlueLightStatus:"), ctypes.byref(buf)):
        return None
    # Layout measured 2026-10-02 on 26A428 with Mark's sunset-to-sunrise schedule on:
    # bytes 01 00 01 00 | 01 00 00 00 → active=1, enabled=0, sun-schedule permitted=1,
    # mode=1 (0 off, 1 sunset to sunrise, 2 custom hours). mode is read so a caller
    # knows a schedule holds the switch BEFORE acting.
    return {"active": bool(buf[0]), "enabled": bool(buf[1]),
            "mode": int.from_bytes(bytes(buf[4:8]), "little", signed=True)}


def low_power_state():
    m = re.search(r"lowpowermode\s+(\d)", sh(["pmset", "-g"], 5)[1])
    return None if not m else m.group(1) == "1"


def bt_power_state():
    ctl, _ = bt_devices()
    return (ctl or {}).get("power")


def builtin_brightness():
    v = status_brightness()[2]
    return (v or {}).get("built_in_percent")


def run_bridge_switch(what, state):
    """Bluetooth / Night Shift / Low Power through the bridge, verified by readback."""
    read = {"bluetooth": lambda: bt_power_state(),
            "nightshift": lambda: (lambda n: None if n is None else ("on" if n["active"] else "off"))(night_shift_state()),
            "lowpower": lambda: (lambda b: None if b is None else ("on" if b else "off"))(low_power_state())}[what]
    names = {"bluetooth": "Bluetooth", "nightshift": "Night Shift", "lowpower": "Low Power Mode"}
    before = read()
    if before == state:
        return "verified", {what: before}, {what: before, "speak": f"{names[what]} is already {state}.", "units": {}}, \
            f"{names[what]} already {state}", {"already": True}
    if what == "nightshift":
        # Witnessed with Mark 2026-10-02: under a schedule (mode 1, active by sunset) the
        # Shortcut's "off" ran twice, 8-14 s each, and the screen never changed (active
        # stayed 1). The action sets the manual switch, which the schedule overrides. A
        # no-op is refused before it runs, with the schedule named and the pane that
        # changes it; it never spends a Shortcut run to report MISMATCHED.
        ns = night_shift_state() or {}
        if ns.get("mode"):
            sched = {1: "sunset to sunrise", 2: "custom hours"}.get(ns["mode"], f"mode {ns['mode']}")
            raise Refusal("schedule-active",
                          f"Night Shift is on a schedule ({sched}); the Shortcut's switch cannot override it "
                          f"— change the schedule in Displays › Night Shift",
                          fix="system.pane.displays.nightshiftsection", schedule=sched)
    rc, err = bridge_run(f"{what} {state}")
    if rc != 0:
        return "failed", {what: before}, None, f"the hilt Shortcut failed: {err[:200]}", {}
    after = poll(read, lambda v: v == state, 8)
    b, a = {what: before}, {what: after, "speak": f"{names[what]} is {after}.", "units": {}}
    if after != state:
        return "mismatched", b, a, (f"the Shortcut ran but {names[what]} reads {after}, not {state} "
                                    "(if this repeats, the bridge's action keys are wrong: tell hilt)"), {}
    return "verified", b, a, f"{names[what]} {before} -> {after}", {"via": "shortcut: hilt"}


def run_brightness(level):
    cur = builtin_brightness()
    if cur is None:
        raise Refusal("not-settable", "no built-in screen brightness here; external displays set their own.")
    want = min(100, (cur // 10 + 1) * 10) if level == "up" else max(0, ((cur + 9) // 10 - 1) * 10) if level == "down" \
        else int(round(int(level) / 10.0) * 10)
    rc, err = bridge_run(f"brightness {want}")
    if rc != 0:
        return "failed", {"brightness_percent": cur}, None, f"the hilt Shortcut failed: {err[:200]}", {}
    after = poll(builtin_brightness, lambda v: v is not None and abs(v - want) <= 6, 5)
    b, a = {"brightness_percent": cur}, {"brightness_percent": after, "units": {"brightness_percent": "%"},
                                         "speak": f"Screen brightness is {after} percent."}
    if after is None or abs(after - want) > 6:
        return "mismatched", b, a, f"asked for {want}% but the screen reads {after}%", {}
    return "verified", b, a, f"brightness {cur}% -> {after}% (steps of 10)", \
        {"via": "shortcut: hilt", "already": abs(cur - want) <= 6}


# ---- CUT F, slice 1: an app's own scripting commands, the SAFE no-argument ones.
# ONE fixed JXA script (its text never varies: the falsifier of spec §7 CUT F); the bundle id
# and the command arrive as argv. An ALLOWLIST, not a deny-list: "sleep" is not flagged
# irreversible yet would put the Mac to sleep on a mishearing, so only these names run.
SAFE_VERBS = {"play", "pause", "playpause", "stop", "resume", "nexttrack", "previoustrack", "backtrack",
              "rewind", "nextslide", "previousslide", "pauseslideshow", "resumeslideshow", "stopslideshow",
              "shownext", "showprevious", "startslideshow", "checkfornewmail", "reloadcalendars",
              "showbookmarks", "showprivacyreport", "newwindow", "newtab", "createwindowwithdefaultprofile"}
VERB_JXA = r"""function run(argv) {
  var bid = argv[0], cmd = argv[1], prop = argv[2] || "";
  var app = Application(bid);
  if (!app.running()) return JSON.stringify({ok: false, why: "not-running"});
  var read = function () { if (!prop) return null; try { return String(app[prop]()); } catch (e) { return null; } };
  var before = read();
  if (typeof app[cmd] !== "function") return JSON.stringify({ok: false, why: "no-such-command"});
  try { app[cmd](); } catch (e) { return JSON.stringify({ok: false, why: "error", error: String(e)}); }
  delay(0.4);
  return JSON.stringify({ok: true, before: before, after: read()});
}"""
# A witness where the app has one: (bundle, verb) -> (property, expected after | "changed")
VERB_PROBES = {}
for _b in ("com.apple.Music", "com.spotify.client", "com.apple.TV"):
    VERB_PROBES.update({(_b, "play"): ("playerState", "playing"), (_b, "pause"): ("playerState", "paused"),
                        (_b, "stop"): ("playerState", "stopped"), (_b, "playpause"): ("playerState", "changed")})


def jxa_name(command):
    w = command.split()
    return w[0].lower() + "".join(x[:1].upper() + x[1:] for x in w[1:])


def run_verb(rec):
    verb, bid = rec["id"].split(".do.", 1)[1], rec["x_bundle"]
    if [p for p in rec.get("x_params") or [] if not p.get("optional")]:
        raise Refusal("not-shipped", f"{rec['id']} takes arguments; CUT F slice 1 runs only no-argument "
                      "commands (typed arguments come in a later slice).")
    if verb not in SAFE_VERBS or rec.get("x_irreversible"):
        raise Refusal("not-shipped", f"{rec['id']} is not on the safe-command allowlist (media, slideshow, "
                      "new window/tab, check mail). Quit, sleep, shut down, empty and the like wait for an "
                      "explicit confirmation contract.")
    if not rec.get("x_command"):
        raise Refusal("stale-index", "this index predates x_command; run `hilt build`.")
    if app_pid(bid) is None:
        raise Refusal("not-running", f"{bid} is not running; hilt does not launch an app to send it a command. "
                      f"Open it first (`hilt run app.{bid}`).")
    allow = "--allow-prompt" in OPTS
    app = responsible_app()
    st = tcc_state(app, "kTCCServiceAppleEvents", bid) if app else "unknown"
    if not allow and st == "unknown":
        # the §33 rule: a TCC database hilt cannot read proves nothing (measured 2026-10-06:
        # Spotify play/pause refused "would prompt" from a sandboxed shell while the grant existed)
        raise Refusal("permission-unverifiable", f"whether the host ({app or 'unknown'}) holds Automation for {bid} "
                      "cannot be read from here (TCC database unreadable). Not refused as missing — unknown. "
                      "Rerun with --allow-prompt (a prompt may appear), or from a host that can read TCC.",
                      service="kTCCServiceAppleEvents", target=bid, tcc="unreadable")
    if not allow and st != "allowed":
        raise Refusal("permission-would-prompt", f"sending {bid} a command needs the host app's Automation "
                      f"grant for it ({st}); macOS would prompt and the call would hang. Allow it once (rerun with "
                      "--allow-prompt while a person watches), then it is silent.", fix="Privacy_Automation")
    prop, want = VERB_PROBES.get((bid, verb), ("", None))
    rc, out, err = sh(["osascript", "-l", "JavaScript", "-e", VERB_JXA, bid, jxa_name(rec["x_command"]), prop],
                      60 if allow else 15)
    try:
        r = json.loads(out.strip().splitlines()[-1])
    except (ValueError, IndexError):
        return "failed", None, None, f"osascript: {(err or out).strip()[:200]}", {}
    if not r.get("ok"):
        if r.get("why") == "not-running":
            raise Refusal("not-running", f"{bid} quit before the command arrived.")
        return "failed", None, None, f"{rec['x_command']}: {r.get('why')} {r.get('error', '')}".strip(), {}
    b, a = {prop: r.get("before")} if prop else None, {prop: r.get("after")} if prop else None
    if not prop:
        return "unverifiable", None, None, f"{rec['x_command']} sent to {bid}; this app exposes no state to read back", {}
    ok = (r.get("after") != r.get("before")) if want == "changed" else (r.get("after") == want)
    if not ok:
        return "mismatched", b, a, f"{rec['x_command']} sent; {prop} reads {r.get('after')!r}", {}
    a["speak"] = {"playing": "Playing.", "paused": "Paused.", "stopped": "Stopped."}.get(r.get("after"), "Done.")
    a["units"] = {}
    return "verified", b, a, f"{rec['x_command']}: {prop} {r.get('before')} -> {r.get('after')}", {}


def run_cli(rec, vals):
    """A setter with a paired getter: the getter's output before and after."""
    given = dict(vals)
    probe = None
    if rec.get("x_probe_argv"):
        need = rec.get("x_probe_params") or []
        if all(n in given for n in need):
            probe = rec["x_probe_argv"] + [given[n] for n in need]

    def read():
        rc, out, _ = sh(probe, 20)
        return {"output": out.strip() if rc == 0 else None}

    before = read() if probe else None
    rc, out, err = sh(rec["x_argv"] + [v for _, v in vals], 60)
    if rc != 0:
        return "failed", before, None, f"{rec['x_argv'][0]} exited {rc}: {(err or out).strip()[:200]}", {}
    if not probe:
        return "unverifiable", None, None, "exited 0; no paired getter can observe this setter", {}
    after = poll(read, lambda s: s["output"] != before["output"], 5)
    if after["output"] == before["output"]:
        return "mismatched", before, after, ("exited 0 but the paired getter did not move — a no-op "
                                             "(already in that state, or the write was ignored)"), {}
    return "verified", before, after, f"{before['output']!r} -> {after['output']!r}", {}


def diskutil_volumes():
    """[{id, name, mount, external}] from diskutil's own plist (live)."""
    rc, out, _ = sh(["diskutil", "list", "-plist"], 20)
    if rc != 0:
        return None
    try:
        pl = plistlib.loads(out.encode())
    except Exception:
        return None
    vols = []
    for d in pl.get("AllDisksAndPartitions", []):
        for v in [d] + d.get("APFSVolumes", []) + d.get("Partitions", []):
            if v.get("DeviceIdentifier"):
                vols.append({"id": v["DeviceIdentifier"], "name": v.get("VolumeName"), "mount": v.get("MountPoint"),
                             "external": None})
    return vols


def volume_external(ident):
    rc, out, _ = sh(["diskutil", "info", ident], 20)
    m = re.search(r"Device Location:\s+(\w+)", out) if rc == 0 else None
    return (m.group(1).lower() == "external") if m else None


def resolve_volume(a, external_only=False):
    vols = diskutil_volumes()
    if vols is None:
        raise Refusal("failed", "diskutil did not list volumes.")
    want = a.lower().lstrip("/dev/").strip()
    hit = [v for v in vols if v["id"].lower() == want]
    if not hit:  # by name or mount point; a sealed snapshot volume (diskNsMsK) stands in for
        hit = [v for v in vols if ((v["name"] or "").lower() == want or (v["mount"] or "").lower() == a.lower())
               and not re.fullmatch(r"disk\d+s\d+s\d+", v["id"])]  # its parent and is never the one meant
    if not hit:
        names = sorted({v["name"] for v in vols if v["name"]})
        raise Refusal("bad-enum", f"'{a}' is not a volume here (identifier, name or mount point). Volumes: "
                                  + ", ".join(names[:12]))
    if len(hit) > 1 and len({v["id"] for v in hit}) > 1:
        raise Refusal("ambiguous", f"'{a}' names {len(hit)} volumes: " + ", ".join(v["id"] for v in hit))
    v = hit[0]
    if external_only and volume_external(v["id"]) is not True:
        raise Refusal("internal-volume", f"{v['id']} ({v['name']}) is not an external volume; hilt only "
                                         "unmounts, mounts or ejects external ones.", volume=v["id"])
    return v["id"]


def primary_network(kind):
    """The device carrying the default route, or the service that owns it."""
    rc, out, _ = sh(["route", "-n", "get", "default"], 10)
    m = re.search(r"interface:\s+(\S+)", out) if rc == 0 else None
    dev = m.group(1) if m else None
    if kind == "networksetup.device" or not dev:
        return dev
    rc, out, _ = sh(["networksetup", "-listnetworkserviceorder"], 15)
    m = re.search(r"\(\d+\) ([^\n]+)\n\(Hardware Port: [^,]+, Device: " + re.escape(dev) + r"\)", out) if rc == 0 else None
    return m.group(1).strip() if m else None


def sim_devices():
    """[{name, udid, state, runtime}] from simctl's own JSON (available devices)."""
    rc, out, _ = sh(["xcrun", "simctl", "list", "devices", "available", "-j"], 30)
    if rc != 0:
        return None
    try:
        devs = json.loads(out).get("devices", {})
    except ValueError:
        return None
    return [dict(name=d["name"], udid=d["udid"], state=d.get("state"), runtime=rt.rsplit(".", 1)[-1]) for rt, lst in devs.items() for d in lst]


def resolve_sim(a):
    devs = sim_devices()
    if devs is None:
        raise Refusal("failed", "simctl did not list devices (is Xcode selected? `hilt run state.dev.xcode`).")
    if not devs:
        raise Refusal("bad-enum", "no simulators are installed on this Mac (Xcode › Settings › Components).", devices=[])
    hit = [d for d in devs if d["udid"].lower() == a.lower()] or [d for d in devs if d["name"].lower() == a.lower()] or \
          [d for d in devs if norm(d["name"]) == norm(a)]
    if not hit:
        raise Refusal("bad-enum", f"'{a}' is not a simulator here. Devices: " + ", ".join(sorted({d['name'] for d in devs})[:12]), devices=sorted({d["name"] for d in devs}))
    if len(hit) > 1:  # same name under several runtimes: prefer a booted one, else refuse with the UDIDs
        booted = [d for d in hit if d["state"] == "Booted"]
        if len(booted) == 1:
            return booted[0]["udid"]
        raise Refusal("ambiguous", f"'{a}' exists under {len(hit)} runtimes: " + ", ".join(f"{d['runtime']} {d['udid']}" for d in hit) + " — give the UDID.")
    return hit[0]["udid"]


def launchd_labels():
    """{label: plist path or None} for this user: what launchctl lists now, plus every
    plist in ~/Library/LaunchAgents (loaded or not)."""
    rc, out, _ = sh(["launchctl", "list"], 15)
    labels = {l.split("\t")[-1].strip(): None for l in out.splitlines()[1:] if l.strip()} if rc == 0 else {}
    d = os.path.expanduser("~/Library/LaunchAgents")
    for f in (os.listdir(d) if os.path.isdir(d) else []):
        if f.endswith(".plist") and not f.startswith("."):
            labels[f[:-6]] = os.path.join(d, f)
    return labels


def resolve_launchd_label(a, user_agent_only=False):
    labels = launchd_labels()
    if not re.fullmatch(r"[A-Za-z0-9._-]{1,200}", a):
        raise Refusal("bad-type", f"'{a}' is not a launchd label.")
    hit = [l for l in labels if l.lower() == a.lower()] or [l for l in labels if norm(l) == norm(a)] or \
          [l for l in labels if a.lower() in l.lower()]
    if not hit:
        raise Refusal("bad-enum", f"'{a}' is not a launchd label loaded for this user or a plist in ~/Library/LaunchAgents. "
                                  f"`hilt run cli.launchctl.list` lists them.", labels=sorted(labels)[:20])
    if len(hit) > 1 and len({h.lower() for h in hit}) > 1:
        raise Refusal("ambiguous", f"'{a}' matches {len(hit)} labels: " + ", ".join(sorted(hit)[:8]))
    label = hit[0]
    if user_agent_only and not labels.get(label):
        raise Refusal("not-a-user-agent", f"{label} has no plist in ~/Library/LaunchAgents (a system agent or daemon is root's; "
                                           "a login item set in Settings is not a launchd plist).")
    return label


def ns_services():
    rc, out, _ = sh(["networksetup", "-listallnetworkservices"], 15)
    return [l.lstrip("*").strip() for l in out.splitlines()[1:] if l.strip()] if rc == 0 else []


def ns_devices():
    rc, out, _ = sh(["networksetup", "-listallhardwareports"], 15)
    return re.findall(r"^Device: (\S+)$", out, re.M) if rc == 0 else []


def resolve_ns_service(a):
    """'wifi' / 'Wi-Fi' / 'thunderbolt bridge' → the exact service name networksetup lists."""
    svcs = ns_services()
    if not svcs:
        raise Refusal("failed", "networksetup did not list network services.")
    hit = [x for x in svcs if x.lower() == a.lower()] or [x for x in svcs if norm(x) == norm(a)]
    if not hit:
        raise Refusal("bad-enum", f"'{a}' is not a network service here. Services: " + ", ".join(svcs))
    return hit[0]


def resolve_app_record(a):
    apps = [r for r in load()["records"] if r["kind"] == "application.launch"]
    want, wn = a.lower(), norm(a)
    hit = [r for r in apps if r["x_bundle"].lower() == want or want in [x.lower() for x in r.get("x_aliases", [])]
           or wn in {norm(x) for x in r.get("x_aliases", [])} or wn == norm(r["outcome"][len("open "):])]
    if not hit:
        raise Refusal("bad-enum", f"'{a}' is not an app in the index (name or bundle id). `hilt find {a}`.")
    bundles = sorted({r["x_bundle"] for r in hit})
    if len(bundles) > 1:
        raise Refusal("ambiguous", f"'{a}' names {len(bundles)} apps: " + ", ".join(bundles))
    return next(r for r in hit if r["x_bundle"] == bundles[0])


def resolve_app_process(a):
    """An app → the process name `log show` filters on (CFBundleExecutable), read from the
    app's own Info.plist; falls back to the bundle name."""
    r = resolve_app_record(a)
    path = (r.get("x_paths") or [None])[0]
    info = read_plist(os.path.join(path, "Contents", "Info.plist")) if path else None
    exe = (info or {}).get("CFBundleExecutable") or os.path.basename(path or "").replace(".app", "")
    if not exe or not re.fullmatch(r"[A-Za-z0-9 ._+-]{1,120}", exe):
        raise Refusal("bad-type", f"{r['x_bundle']} has no usable executable name ({exe!r}).")
    return exe


def resolve_running_app(a):
    """An app named the way `find` names them (name, alias or bundle id) → its pid.
    Refused `bad-enum` when the index has no such app, `not-running` when it is
    not running: a force quit never guesses a process by name."""
    apps = [r for r in load()["records"] if r["kind"] == "application.launch"]
    want, wn = a.lower(), norm(a)
    hit = [r for r in apps if r["x_bundle"].lower() == want or want in [x.lower() for x in r.get("x_aliases", [])]
           or wn in {norm(x) for x in r.get("x_aliases", [])}]
    if not hit:
        raise Refusal("bad-enum", f"'{a}' is not an app in the index (name or bundle id). `hilt find {a}`.")
    bundles = sorted({r["x_bundle"] for r in hit})
    if len(bundles) > 1:
        raise Refusal("ambiguous", f"'{a}' names {len(bundles)} apps: " + ", ".join(bundles))
    pid = app_pid(bundles[0])
    if not pid:
        raise Refusal("not-running", f"{bundles[0]} is not running; nothing to quit.", bundle=bundles[0])
    return pid


def cli_fill(argv, vals, extra=None):
    """Substitute {param} / {param*N} into fixed argv; drop a bare token whose
    optional param was not given. Values come only from typed_args."""
    given = dict({"home": os.path.expanduser("~"), "uid": str(os.getuid())}, **dict(vals), **(extra or {}))
    out = []
    for tok in argv:
        m = CLI_PLACEHOLDER.fullmatch(tok)
        if m and m.group(1) not in given:
            continue  # optional, not given
        def sub(mm):
            v = given[mm.group(1)]
            return str(int(v) * int(mm.group(3))) if mm.group(3) else str(v)
        out.append(CLI_PLACEHOLDER.sub(sub, tok))
    return out


DETACHED = os.environ.get("HILT_DETACHED") or os.path.join(STATE, "hilt", "detached.json")


def detached_pids():
    try:
        return json.load(open(DETACHED))
    except (OSError, ValueError):
        return {}


def run_cli_authored(rec, vals):
    """CUT H setter: act (foreground, detached, or release a detached pid), then
    judge by the row's probe. No probe → unverifiable, said so."""
    probe = rec.get("x_cli_probe") or {}
    extra = {}
    if rec.get("x_release"):
        pids = detached_pids()
        pid = pids.get(rec["x_release"])
        if not pid:
            raise Refusal("nothing-to-release", f"hilt holds no detached {rec['x_release']} to end "
                                                f"(`hilt run {rec['x_release']} <minutes>` starts one).")
        try:
            os.killpg(pid, signal.SIGTERM)
        except ProcessLookupError:
            pass
        except PermissionError:
            return "failed", None, None, f"could not signal pid {pid}", {}
        pids.pop(rec["x_release"], None)
        json.dump(pids, open(DETACHED, "w"))
        extra["pid"] = pid
        before = {"pid": pid}
    elif rec.get("x_detach"):
        argv = cli_fill(rec["x_argv"], vals)
        pids = detached_pids()
        old = pids.get(rec["id"])
        if old:
            try:
                os.killpg(old, signal.SIGTERM)  # one at a time: the new span replaces the old
            except (ProcessLookupError, PermissionError):
                pass
        p = subprocess.Popen(argv, start_new_session=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        pids[rec["id"]] = p.pid
        os.makedirs(os.path.dirname(DETACHED), exist_ok=True)
        json.dump(pids, open(DETACHED, "w"))
        extra["pid"] = p.pid
        before = {"pid": old}
    else:
        argv = cli_fill(rec["x_argv"], vals)
        before = None
        if probe.get("kind") == "paired":
            rc0, out0, _ = sh(cli_fill(probe["argv"], vals), 20)
            before = {"output": out0.strip() if rc0 == 0 else None}
        if rec.get("x_cli_before"):  # a read the row asks for before acting (the quarantine mark, to put back)
            b = rec["x_cli_before"]
            rcb, outb, errb = sh(cli_fill(b["argv"], vals), 20)
            before = dict(before or {}, **{"output": outb.strip() if rcb in (b.get("ok_rc") or [0]) and rcb == 0 else None,
                                           "exit": rcb})
        if probe.get("kind") == "file" and probe.get("negate") and not os.path.exists(dict(vals)[probe["param"]]):
            return "verified", before, {"path": dict(vals)[probe["param"]], "exists": False}, "already gone", {"already": True}
        if probe.get("kind") == "regex" and probe.get("argv"):
            # already in the wanted state? then nothing to do, said so (never a spurious `failed`:
            # `xattr -d` of an absent mark exits 1)
            pat0 = CLI_PLACEHOLDER.sub(lambda m: re.escape(str(dict(vals)[m.group(1)])), probe["expect"])
            rc0, out0, err0 = sh(cli_fill(probe["argv"], vals), 20)
            if bool(re.search(pat0, out0 + err0, re.M)) == (not probe.get("negate")):
                return "verified", before, {"matched": not probe.get("negate"), "output": (out0 + err0).strip()[-400:]}, \
                    f"already so: probe `{' '.join(probe['argv'])}` {'matches' if not probe.get('negate') else 'does not match'} /{pat0}/", \
                    {"already": True}
        if rec.get("x_stdin"):
            spath = dict(vals)[CLI_PLACEHOLDER.fullmatch(rec["x_stdin"]).group(1)]
            with open(spath, "rb") as fh:
                pr = subprocess.run(argv, stdin=fh, capture_output=True, text=True, timeout=120)
            rc, out, err = pr.returncode, pr.stdout, pr.stderr
        else:
            rc, out, err = sh(argv, 120)
        if rc != 0:
            return "failed", before, None, f"{argv[0]} exited {rc}: {(err or out).strip()[:200]}", {}
    if not probe:
        return "unverifiable", before, None, "exited 0; this row authors no probe", extra
    if probe["kind"] == "file":
        path = dict(vals)[probe["param"]]
        want_gone = bool(probe.get("negate"))
        ok = poll(lambda: os.path.exists(path) != want_gone, bool, 5)
        return ("verified" if ok else "mismatched"), before, {"path": path, "exists": os.path.exists(path)}, \
            ((f"{path} is gone" if want_gone else f"wrote {path}") if ok else
             (f"exited 0 but {path} still exists" if want_gone else f"exited 0 but {path} does not exist")), extra
    if probe["kind"] == "paired":
        rc1, out1, _ = sh(cli_fill(probe["argv"], vals), 20)
        after = {"output": out1.strip() if rc1 == 0 else None}
        moved = after["output"] != before["output"]
        return ("verified" if moved else "mismatched"), before, after, \
            (f"{before['output']!r} -> {after['output']!r}" if moved else "exited 0 but the paired getter did not move"), extra
    pat = CLI_PLACEHOLDER.sub(lambda m: re.escape(str(dict(vals, **{k: str(v) for k, v in extra.items()})[m.group(1)])),
                              probe["expect"])
    want = not probe.get("negate")

    def read():
        rc2, out2, err2 = sh(cli_fill(probe["argv"], vals, extra), 20)
        return {"matched": bool(re.search(pat, out2 + err2, re.M)), "output": (out2 + err2).strip()[-400:]}
    after = poll(read, lambda s: s["matched"] == want, 6)
    ok = after["matched"] == want
    return ("verified" if ok else "mismatched"), before, after, \
        (f"probe `{' '.join(probe['argv'])}` {'matched' if want else 'no longer matches'} /{pat}/" if ok else
         f"exited 0 but probe `{' '.join(probe['argv'])}` {'did not match' if want else 'still matches'} /{pat}/"), extra


CONFIRMS = os.environ.get("HILT_CONFIRMS") or os.path.join(STATE, "hilt", "confirm.json")
CONFIRM_TTL = 60


def confirm_gate(rec, args):
    """CUT F slice 2: an action that must not run on a mishearing. Without a token:
    REFUSED `confirm-required` carrying a one-time token bound to THIS id + args,
    good for CONFIRM_TTL seconds, and the exact replay line. With a matching,
    unexpired token: it is consumed and the action proceeds. A token for other
    args, or an old one, is refused — never "close enough"."""
    try:
        store = json.load(open(CONFIRMS))
    except (OSError, ValueError):
        store = {}
    now = int(time.time())
    store = {k: v for k, v in store.items() if now - v.get("ts", 0) <= CONFIRM_TTL}  # expire
    want = {"id": rec["id"], "args": list(args)}
    tok = CONFIRM_TOKEN
    if tok and tok in store and store[tok]["id"] == want["id"] and store[tok]["args"] == want["args"]:
        store.pop(tok)
        os.makedirs(os.path.dirname(CONFIRMS), exist_ok=True)
        json.dump(store, open(CONFIRMS, "w"))
        return
    import secrets
    new = secrets.token_hex(4)
    store[new] = dict(want, ts=now)
    os.makedirs(os.path.dirname(CONFIRMS), exist_ok=True)
    json.dump(store, open(CONFIRMS, "w"))
    replay = f"hilt run {rec['id']}" + "".join(" " + shlex.quote(a) for a in args) + f" --confirm={new}"
    why_tok = ("expired or already used" if tok and tok not in store else
               "for a different action" if tok else "none given")
    raise Refusal("confirm-required",
                  f"{rec['id']} acts on a mishearing just as well as on a wish ({rec['outcome'][:60]}). Token "
                  f"{why_tok}. Confirm within {CONFIRM_TTL} s: {replay}",
                  token=new, expires_in=CONFIRM_TTL, confirm_command=replay,
                  speak=f"Say yes to {rec.get('x_label') or rec['id']}.")


def run_pane(rec):
    url = rec["provider"].split(":", 1)[1]
    title = rec["outcome"][len("open "):] if rec["outcome"].startswith("open ") else rec["outcome"]
    if os.environ.get("HILT_NO_OPEN") == "1":
        return {"opened": False, "human_must": f"finish the change by hand in {title} (not opened: HILT_NO_OPEN)"}
    rc, _, _ = sh(["open", url], 20)
    return {"opened": rc == 0, "human_must": f"finish the change by hand in {title}"}


def dispatch(rec, args, no_reload):
    kind, auth = rec["kind"], rec["authority"]
    if auth == "requires_sudo":
        fix, extra, hc = rec.get("x_fix"), {}, None
        if rec.get("x_command") and (args or not rec.get("x_params")
                                     or all(p.get("optional") or p.get("default_from") for p in rec["x_params"])):
            vals = typed_args(rec, args)  # refuses a bad state before rendering anything; defaults fill the rest
            hc = rec["x_command"]
            for n, v in vals:
                hc = hc.replace("{" + n + "}", v)
            extra["human_command"] = hc
        elif rec.get("x_command"):  # no state given: still the sudo answer, with the shape
            extra["human_command_template"] = rec["provider"]
        if fix:
            extra["fix"] = fix
        raise Refusal("requires-sudo", f"{rec['id']} needs root, and sudo cannot prompt from an "
                                       "agent. Listed, never run. See `hilt traps sudo-cannot-prompt`."
                      + (f" A human can paste: {hc} ." if hc else "")
                      + (f" Or do it in Settings: hilt run {fix}" if fix else ""), **extra)
    if kind == "application.verb":
        return run_verb(rec)
    if auth == "human-required" and kind != "system.pane":
        raise Refusal("human-required", f"{rec['id']} is human-required: no shell door invokes it. "
                      f"Route to its pane (`hilt find {rec.get('x_bundle', '')}`) or a user Shortcut.")
    vals = typed_args(rec, args)
    if auth == "human-required":
        # Opening the pane IS the record's whole outcome; the change itself is a human's.
        p = run_pane(rec)
        raise Refusal("human-required", f"{rec['id']} is human-required: "
                      + ("the pane was requested (open exited 0; which pane shows is unobservable); "
                         if p["opened"] else "the pane did NOT open; ") + p["human_must"] + ".", **p)
    if auth != "local":
        raise Refusal("bad-record", f"{rec['id']} has authority {auth!r}; run acts only on 'local'.")
    if kind == "system.setting":
        return run_setting(rec, vals, no_reload)
    if kind == "application.launch":
        return run_launch(rec)
    if rec.get("x_native") == "audio.devices":
        devs = audio_devices()
        if devs is None:
            return "failed", None, None, "CoreAudio did not load", {}
        lines = [f"{'*' if d['default_output'] or d['default_input'] else ' '} {d['name']} "
                 f"[{d['transport']}; {'out' if d['output'] else ''}{'+' if d['output'] and d['input'] else ''}"
                 f"{'in' if d['input'] else ''}]"
                 + (" default output" if d["default_output"] else "") + (" default input" if d["default_input"] else "")
                 for d in devs]
        return "query", None, {"devices": devs}, "\n".join(lines), {}
    if rec.get("x_native") == "bluetooth.devices":
        ctl, devs = bt_devices()
        if devs is None:
            return "failed", None, None, "system_profiler SPBluetoothDataType unreadable", {}
        near = {m["name"] for m in mine_nearby(devs)}
        lines = [f"bluetooth power {ctl['power']}"] + (
            [f"yours nearby (live LE link): {', '.join(sorted(near))}"] if near else []) + [
            f"{'*' if d['connected'] else ' '} {d['name']} [{d['kind'] or ('BLE' if d.get('le_only') else '?')}]"
            + (" connected" if d["connected"] else "") + (f" rssi {d['rssi']}" if d.get("rssi") else "")
            + "".join(f" {k}={v}" for k, v in d.items() if "battery" in k) for d in devs]
        return "query", None, {"controller": ctl, "devices": devs, "mine_nearby": mine_nearby(devs)}, "\n".join(lines), {}
    if rec.get("x_native") == "dev.xcode":
        t = dev_toolchain()
        x = t["xcode"] or {}
        rts = t["simulator_runtimes"]
        lines = [f"developer dir: {t['developer_dir'] or 'NONE'} ({t['using'] or 'no toolchain'})",
                 f"Xcode {x.get('version', '—')} ({x.get('build', '—')}) · SDK macOS {t['sdk']['macos']} iOS {t['sdk']['ios']} · Swift {t['swift']}",
                 "simulators: " + ("none installed — iOS simulator builds will fail" if rts == [] else
                                   ", ".join(f"{r['name']}" for r in rts or []) or "unknown")
                 + (f" · {t['simulator_devices']} device(s)" if t["simulator_devices"] else ""),
                 "signing: " + ("; ".join(f"{i['name']}" for i in t["signing_identities"]) or "no valid identity")
                 + f" · provisioning profiles {t['provisioning_profiles']}",
                 f"CLT {t['command_line_tools'] or 'not installed'} · {t['rust']['rustc'] or 'no rustc'} · python for hilt: {t['python_for_hilt']}"]
        return "query", None, t, "\n".join(lines), {}
    if rec.get("x_native") == "resources":
        r, where, err = fixed_script_read(RESOURCES_PY, vals[0][1] if vals else None)
        if r is None:
            return "failed", None, None, f"no resource read from {where}: {err}", {}
        r["where"] = where
        m, w = r["memory"], r["windowserver"]
        lines = [f"{where}: memory pressure {m['pressure_level']} · {m['resident_gb']} GB resident of {m['ram_gb']} GB · "
                 f"swap {m['swap_used_mb']} MB used · WindowServer cpu {w['cpu_samples']} (median {w['cpu_median']}%)"]
        lines += [f"  {a['rss_mb'] / 1024:5.2f} GB  cpu {a['cpu']:5.1f}%  {a['procs']:3} proc  {a['name']}" for a in r["apps"][:10]]
        if r.get("chrome"):
            lines.append("  Chrome by part: " + ", ".join(f"{k} {v['rss_mb'] / 1024:.2f} GB/{v['cpu']}%/{v['procs']}p"
                                                          for k, v in sorted(r["chrome"].items(), key=lambda kv: -kv[1]["rss_mb"])))
        lines.append("  (evidence, not blame: quit one thing and re-read to prove a culprit)")
        return "query", None, r, "\n".join(lines), {}
    if rec.get("x_native") == "fleet.macs":
        peers = tailnet_macs()
        if peers is None:
            return "failed", None, None, "tailscale is not installed or not answering", {}
        lines = [f"{'*' if p['self'] else ' '} {p['name']:<22} {'online ' if p['online'] else 'offline'} "
                 f"{p['ip'] or '':<16} {p['path'] or '(this Mac)'}" for p in peers]
        return "query", None, {"macs": peers}, "\n".join(lines), {}
    if rec.get("x_native") == "thermal.sensors":
        sensors, where, err = thermal_read(vals[0][1] if vals else None)
        if sensors is None:
            return "failed", None, None, f"no sensor read from {where}: {err}", {}
        # tcal = a calibration constant, not a reading. And some channels report
        # garbage: this MBA's "PMU tdev1" read -22.1 °C (2026-09-26), which would
        # make "room is at most -22" — so readings outside 0..130 °C are set aside.
        real = [(n, v) for n, v in sensors if "tcal" not in n.lower() and 0 < v < 130]
        implausible = [(n, v) for n, v in sensors if "tcal" not in n.lower() and not 0 < v < 130]
        vs = sorted(v for _, v in real)
        summary = {"where": where, "count": len(real),
                   "coolest": min(real, key=lambda x: x[1]) if real else None,
                   "hottest": max(real, key=lambda x: x[1]) if real else None,
                   "median": vs[len(vs) // 2] if vs else None,
                   "room_upper_bound_c": vs[0] if vs else None,
                   "implausible": [{"name": n, "c": v} for n, v in implausible],
                   "units": {"coolest": "°C", "hottest": "°C", "median": "°C", "room_upper_bound_c": "°C", "c": "°C"}}
        text = (f"{where}: {len(real)} sensors · median {summary['median']} °C · hottest "
                f"{summary['hottest'][0]} {summary['hottest'][1]} °C · coolest {summary['coolest'][0]} "
                f"{summary['coolest'][1]} °C (room is at most this)"
                + (f" · {len(implausible)} implausible reading(s) set aside" if implausible else "")) if real else f"{where}: no sensors"
        speak = (f"The hottest sensor reads {round(summary['hottest'][1])} degrees Celsius, the median "
                 f"{round(summary['median'])}; the room is at most {round(vs[0])} degrees." if real else "No temperature sensors answered.")
        return "query", None, {"summary": summary, "sensors": [{"name": n, "c": v} for n, v in sensors],
                               "units": {"c": "°C"}, "speak": speak}, text, {}
    if rec.get("x_native") in STATUS_READS:
        return status_read(rec["x_native"], vals[0][1] if vals else None)
    if rec.get("x_native") == "focus.set":
        return run_focus_set(vals[0][1])
    if rec.get("x_native") == "audio.volume":
        return run_volume(vals[0][1])
    if rec.get("x_native") == "audio.mute":
        return run_mute(vals[0][1])
    if rec.get("x_native") == "wifi.power":
        return run_wifi_power(vals[0][1])
    if rec.get("x_native") == "appearance.dark":
        return run_dark_mode(vals[0][1])
    if rec.get("x_native") == "screen.lock":
        return run_screen_lock()
    if rec.get("x_native") == "bridge.lowpower":
        # Shortcuts on Mac: "The action Set Low Power Mode is not supported on Mac" (measured
        # 2026-10-01, macOS 27). The only door is pmset, which needs admin: a human runs it.
        want = vals[0][1]
        if low_power_state() == (want == "on"):
            return "verified", {"lowpower": want}, {"lowpower": want, "speak": f"Low Power Mode is already {want}.",
                                                    "units": {}}, f"Low Power Mode already {want}", {"already": True}
        raise Refusal("requires-sudo", "Low Power Mode needs admin on a Mac (Shortcuts' action is iPhone-only). "
                      "A person runs the command below, or flips it in Settings › Battery.",
                      human_command=f"sudo pmset -a lowpowermode {1 if want == 'on' else 0}",
                      fix="system.pane.battery")
    if rec.get("x_native") in ("bridge.bluetooth", "bridge.nightshift"):
        return run_bridge_switch(rec["x_native"].split(".")[1], vals[0][1])
    if rec.get("x_native") == "bridge.brightness":
        return run_brightness(vals[0][1])
    if rec.get("x_native") == "nightshift.read":
        n = night_shift_state()
        if n is None:
            return "failed", None, None, "CoreBrightness did not answer", {}
        on = "on" if n["active"] else "off"
        sched = {0: None, 1: "sunset to sunrise", 2: "custom hours"}.get(n.get("mode"), f"mode {n.get('mode')}")
        return "query", None, {"on": n["active"], "enabled": n["enabled"], "schedule": sched, "units": {},
                               "speak": f"Night Shift is {on}" + (f", on a {sched} schedule." if sched else ".")}, \
            f"Night Shift {on} (enabled={n['enabled']}, schedule={sched})", {}
    if rec.get("x_native") == "quarantine.agents":
        q = quarantine_scan((load().get("setup_profiles") or {}).get("_quarantine:dev", []))
        marked = [x for x in q if x["state"] == "quarantined"]
        lines = [f"{len(marked)} of {len([x for x in q if x['state'] != 'absent'])} agent binaries quarantined"]
        lines += [f"  {x['binary']}: {x['path']}  clear (human): {x['human_command']}" for x in marked]
        return "query", None, {"binaries": q, "quarantined": [x["binary"] for x in marked]}, "\n".join(lines), {}
    if rec.get("x_native") == "bluetooth.mine-nearby":
        _, devs = bt_devices()
        if devs is None:
            return "failed", None, None, "system_profiler SPBluetoothDataType unreadable", {}
        # ONE-DIRECTIONAL evidence (walk-away 2026-09-24): a live link means in
        # range (the LE twin tracked RSSI -63..-80 as Mark walked out, then
        # dropped). NO link means UNKNOWN, never "not nearby": back in the room,
        # lid opened, even classic-connected, the twin did not re-form.
        near = {m["name"]: {"name": m["name"], "via": "LE link", "rssi": m["rssi"]} for m in mine_nearby(devs)}
        for d in devs:
            if d["connected"] and not d.get("le_only") and d["name"] not in near:
                near[d["name"]] = {"name": d["name"], "via": "connected", "rssi": d.get("rssi")}
        unknown = sorted({d["name"] for d in devs if not d.get("le_only") and d["name"] not in near
                          and d.get("kind") in ("Headphones", "Headset")})
        lines = [("nearby: " + ", ".join(f"{n['name']} ({n['via']}" + (f", rssi {n['rssi']})" if n["rssi"] else ")")
                                         for n in near.values())) if near else "nothing confirmed nearby"]
        if unknown:
            lines.append("  unknown (no live link — absence is not evidence of distance): " + ", ".join(unknown))
        return "query", None, {"nearby": list(near.values()), "unknown": unknown}, "\n".join(lines), {}
    if rec.get("x_native") == "wifi.scan":
        return run_wifi_scan()
    if rec.get("x_native") == "wifi.join":
        return run_wifi_join(vals[0][1])
    if rec.get("x_native") == "bluetooth.nearby":
        return run_bt_nearby(int(vals[0][1]) if vals else 8, "--allow-prompt" in OPTS)
    if rec.get("x_native") in ("bluetooth.connect", "bluetooth.disconnect"):
        return run_bt(rec["x_native"].split(".")[1], vals[0][1], "--allow-prompt" in OPTS)
    if (rec.get("x_native") or "").startswith("audio.set."):
        return run_audio_set(rec["x_native"].rsplit(".", 1)[1], vals[0][1])
    if kind == "system.state" and rec.get("x_verb") == "permissions":
        if len(args) > 1:
            raise Refusal("bad-args", f"{rec['id']} takes at most one app. `hilt describe {rec['id']}`.")
        obj, text, code = permissions_answer(load(), args)
        if code == 3:
            raise Refusal("bad-enum", text[len("VACUOUS "):], query=args[0] if args else None)
        if code != 0:
            return "failed", None, obj, text, {}
        return "query", None, obj, text, {}
    if kind == "system.state" and rec.get("x_witness"):
        return run_witness(rec)
    if rec.get("x_cli_authored") and rec.get("x_preflight"):
        svc, tgt = CLI_PREFLIGHTS[rec["x_preflight"]]
        app = responsible_app()
        st = tcc_state(app, svc, tgt) if app else "unknown"
        if st == "unknown" and "--allow-prompt" not in OPTS:
            raise Refusal("permission-unverifiable", f"{rec['id']} sends one fixed line to {tgt}; whether the host "
                          f"({app or 'unknown'}) holds Automation for it cannot be read (the TCC database is not readable "
                          "from here: Full Disk Access, or a sandboxed shell). Not refused as missing — unknown. Run with "
                          "--allow-prompt to proceed (a prompt may appear), or from a host that can read TCC.",
                          service=svc, target=tgt, tcc="unreadable")
        if st != "allowed" and st != "unknown":
            raise Refusal("permission-would-prompt", f"{rec['id']} sends one fixed line to {tgt} and the host "
                          f"({app or 'unknown'}) does not hold Automation for it ({st}); a prompt mid-task is never raised. "
                          f"Grant it: hilt setup dev (trigger {rec['x_preflight']}).",
                          fix="system.pane.privacysecurity.automation", service=svc, target=tgt)
    if rec.get("x_cli_authored") and rec.get("x_confirm"):
        confirm_gate(rec, args)  # refuses with a token, or lets a matching token through once
    if rec.get("x_cli_authored") and kind == "system.state":
        argv = cli_fill(rec["x_argv"], vals)
        rc, out, err = sh(argv, 120)
        if rc != 0 and rc not in (rec.get("x_ok_rc") or [0]):
            return "failed", None, {"output": out}, f"{argv[0]} exited {rc}: {(err or out).strip()[:200]}", {}
        return "query", None, {"output": out, "exit": rc}, (out + ("" if out.strip() else err)).rstrip() or f"(nothing; exit {rc})", {}
    if rec.get("x_cli_authored"):
        return run_cli_authored(rec, vals)
    if kind == "system.state" and rec.get("x_argv"):
        return run_query(rec, vals)
    if kind == "system.cli" and rec.get("x_argv"):
        return run_cli(rec, vals)
    if kind == "shortcut.run" and rec.get("x_argv"):
        rc, out, err = sh(rec["x_argv"], 120)
        if rc != 0:
            return "failed", None, None, f"shortcuts run exited {rc}: {(err or out).strip()[:200]}", {}
        return "unverifiable", None, None, "shortcut ran; its effect is opaque to hilt (no probe authored)", {}
    raise Refusal("not-runnable", f"{rec['id']} ({kind}) carries no actuator run may execute.")


def log_run(row):
    try:
        os.makedirs(os.path.dirname(RUNS), exist_ok=True)
        with open(RUNS, "a") as f:
            f.write(json.dumps(row, default=str) + "\n")
    except OSError as e:
        row["log_error"] = str(e)


def cmd_run(args):
    no_reload = "--no-reload" in OPTS
    t0 = time.time()
    rid, rargs = (args[0], args[1:]) if args else (None, [])
    before = after = None
    extra = {}
    try:
        if not rid:
            raise Refusal("no-id", "run needs an id from `hilt find`, e.g. `hilt run system.dock.autohide true`")
        idx = load()
        rec = next((r for r in idx["records"] if r["id"] == rid), None)
        if not rec:
            near = [r["id"] for r in idx["records"] if rid.lower() in r["id"].lower()][:5]
            raise Refusal("unknown-id", f"{rid} is not an id in the index; nothing was run." +
                          (f" Did you mean: {', '.join(near)}" if near else " Try `hilt find <words>`."),
                          suggest=near)
        # The probe provenance a UI verdict row shows ("read back", "by pid", "no
        # probe") — in the run answer itself, so Zil needs no second describe call.
        extra = {"os_build": idx["os"]["build"], "probe_kind": rec.get("x_probe_kind"), "kind": rec["kind"]}
        verdict, before, after, detail, dextra = dispatch(rec, rargs, no_reload)
        extra.update(dextra)
        why = None
    except Refusal as r:
        verdict, detail, why = "refused", r.detail, r.why
        extra = dict(extra, **r.extra)
    row = {"ts": int(t0), "caller": os.environ.get("HILT_CALLER") or "cli", "id": rid, "args": rargs,
           "no_reload": no_reload, "verdict": verdict,
           "why": why, "before": before, "after": after, "seconds": round(time.time() - t0, 2),
           "detail": detail, **extra}
    log_run({k: (v[:2000] if isinstance(v, str) else v) for k, v in row.items()})
    text = f"{verdict.upper()} {rid or ''}: {detail}".rstrip()
    emit(row, text, RUN_EXIT[verdict])


FLAGS = ("--json", "--all", "--no-reload", "--criteria", "--allow-prompt", "--check", "--pppc", "--list", "--confirm")
OPTS = set()
CONFIRM_TOKEN = os.environ.get("HILT_CONFIRM")  # `--confirm=<token>` sets it too


def help_flags(argv):
    rc, out, err = sh(argv + ["--help"], 5)
    return sorted(set(re.findall(r"(?<![\w-])(--[a-z][a-z0-9-]*)", out + err))) if rc in (0, 1, 2) else None


def cmd_inventory(_):
    """What THIS Mac can do for the fleet, derived live: hardware, OS, the tools
    hilt recommends (present / missing / lacking a needed flag), and local
    models. A tool's version is a banner; the flags its --help lists are what
    a caller may rely on. hilt installs nothing — a missing brew tool carries
    the line for a human (`human_command`)."""
    idx = load()
    rc, out, _ = sh(["system_profiler", "-json", "SPHardwareDataType"], 20)
    try:
        h = json.loads(out)["SPHardwareDataType"][0]
        machine = {k: h.get(k) for k in ("machine_name", "machine_model", "chip_type", "physical_memory")}
    except (ValueError, KeyError, IndexError):
        machine = {"error": "system_profiler SPHardwareDataType unreadable"}
    brew = which("brew")
    rows = []
    for r in idx.get("requirements") or []:
        path = which(r["binary"])
        row = {"id": r["id"], "binary": r["binary"], "provider": r["provider"], "level": r["level"],
               "unlocks": r["unlocks"], "path": path}
        if not path:
            row["status"] = "missing"
            if r["provider"] == "brew":
                row["human_command"] = (f"brew install {r['formula']}" if brew else
                                        f"install Homebrew (https://brew.sh), then: brew install {r['formula']}")
        else:
            rc, vout, verr = sh([path, "--version"], 5)
            row["version"] = ((vout or verr).strip().splitlines() or [""])[0][:80] if rc == 0 else None
            lacking = {}
            for sub, need in (r.get("needs") or {}).items():
                have = help_flags([path, sub])
                miss = need if have is None else [f for f in need if f not in have]
                if miss:
                    lacking[sub] = miss
                row.setdefault("flags", {})[sub] = have
            row["status"] = "lacking" if lacking else "ok"
            if lacking:
                row["lacking"] = lacking
        rows.append(row)
    models = {}
    try:
        import urllib.request
        with urllib.request.urlopen("http://127.0.0.1:11434/api/tags", timeout=1) as f:
            models["ollama"] = sorted(m["name"] for m in json.load(f).get("models", []))
    except Exception:
        models["ollama"] = None  # not reachable: says nothing about what is installed
    if which("vlab"):
        rc, out, _ = sh(["vlab", "models", "list"], 10)
        # Only the indented rows under the "speech-to-text" heading. vlab 0.5.9 added a
        # "local engines" section whose kokoro row SAYS "text-to-speech", which an older
        # split-on-that-phrase read as a whisper model.
        stt, inside = [], False
        for line in out.splitlines():
            if line and not line[0].isspace():
                inside = line.lower().startswith("speech-to-text")
            elif inside:
                stt.append(line)
        models["whisper"] = re.findall(r"✓\s+(\S+)", "\n".join(stt)) if rc == 0 else None
        # Installed is not in use: the sweep's model was once misreported as
        # base.en (not even installed). vlab doctor names the active one.
        rc, out, _ = sh(["vlab", "doctor"], 10)
        m = re.search(r"listen model\s+\W+\s+(\S+)", out)
        models["whisper_active"] = m.group(1) if m else None
    toolchain = dev_toolchain()
    unmet = [x for x in rows if x["status"] != "ok" and x["level"] == "recommended"]
    lines = [f"{machine.get('machine_name')} {machine.get('machine_model')} · {machine.get('chip_type')} · "
             f"{machine.get('physical_memory')} · macOS {idx['os']['version']} ({idx['os']['build']}) · "
             f"hilt contract {HILT_CONTRACT}"]
    for x in rows:
        tail = (x.get("version") or "") if x["status"] == "ok" else (
            f"lacks {x['lacking']}" if x["status"] == "lacking" else f"→ {x.get('human_command') or 'fleet install'}")
        lines.append(f"  {x['status']:<8} {x['id']:<14} {x['level']:<12} {tail}")
    lines.append(f"  models   ollama {models.get('ollama') if models.get('ollama') is not None else '(not reachable)'}"
                 f" · whisper {models.get('whisper')} (active {models.get('whisper_active')})")
    tx = toolchain["xcode"] or {}
    lines.append(f"  toolchain Xcode {tx.get('version', '—')} · Swift {toolchain['swift']} · simulators "
                 f"{len(toolchain['simulator_runtimes'] or [])} · signing identities {len(toolchain['signing_identities'])}"
                 " (hilt run state.dev.xcode)")
    lines.append(f"recommended unmet: {len(unmet)}" + (f" ({', '.join(x['id'] for x in unmet)})" if unmet else ""))
    emit({"verdict": "OK", "machine": machine, "os": idx["os"], "contract": HILT_CONTRACT,
          "requirements": rows, "models": models, "toolchain": toolchain,
          "recommended_unmet": [x["id"] for x in unmet]},
         "\n".join(lines))


# ---------------------------------------------------------------- learn (CLI over clicks)
# Mark 2026-09-26: "are we shaped well for CLI config over macOS vs UI clicks?"
# 57 settings hilt can write vs 615 panes a human clicks. `learn` turns ONE
# human click into a candidate CLI setting: snapshot every defaults domain
# (through cfprefsd, never the plist files), the human flips one control, diff.
# Candidates are PROPOSALS: adopting one is a reviewed edit of
# probes/settings.json, validated at build and proven by the exerciser.

LEARN_DIR = os.environ.get("HILT_LEARN") or os.path.join(STATE, "hilt", "learn")
# Owner bookkeeping that moves on its own (trap owner-relaunch-churn) plus keys
# that are timestamps/counters by name. Volatile keys are ALSO measured per run.
LEARN_CHURN = {"com.apple.dock": {"mod-count", "recent-apps", "persistent-apps", "persistent-others"},
               "com.apple.finder": {"FXRecentFolders"}, "com.apple.spaces": {"SpacesDisplayConfiguration"}}
# Measured 2026-09-26 ('tap to click', a few minutes between start and diff):
# 74 of 76 changes were background writers — iCloud CloudKitAccountInfoCache,
# history tokens, *Date/*Time floats, change counters. A UI toggle is a SCALAR
# whose key does not read like bookkeeping.
LEARN_NOISY = re.compile(r"(timestamp|date|time$|time\b|lastupdate|last[-_ ]?(used|seen|run|check|processed)|"
                         r"recent|window frame|^NSWindow|^NSSplitView|^NSToolbar|count(er)?$|changecount|"
                         r"launchcount|uuid|cache|token|history|heartbeat)", re.I)
RELOAD_OWNER = {"com.apple.dock": "killall Dock", "com.apple.finder": "killall Finder",
                "com.apple.WindowManager": "killall WindowManager", "com.apple.controlcenter": "killall ControlCenter",
                "com.apple.systemuiserver": "killall SystemUIServer", "com.apple.menuextra.clock": "killall ControlCenter",
                "com.apple.screencapture": "killall SystemUIServer"}


def _fingerprint(v):
    """(type, small value or digest): enough to see a change, JSON-safe."""
    t = ptype(v)
    if isinstance(v, (bool, int, float)) or (isinstance(v, str) and len(v) <= 200):
        return [t, v]
    import hashlib
    raw = plistlib.dumps(v, fmt=plistlib.FMT_BINARY) if not isinstance(v, str) else v.encode()
    return [t, "sha1:" + hashlib.sha1(raw).hexdigest()[:12]]


def learn_snapshot():
    from concurrent.futures import ThreadPoolExecutor
    jobs = []
    for host in (False, True):
        rc, out, _ = sh(["defaults"] + (["-currentHost"] if host else []) + ["domains"], 30)
        doms = [d.strip() for d in out.split(",") if d.strip()] if rc == 0 else []
        jobs += [(host, d) for d in doms + ([] if host else ["NSGlobalDomain"])]

    def one(job):
        host, d = job
        rc, out, _ = sh(["defaults"] + (["-currentHost"] if host else []) + ["export", "-g" if d == "NSGlobalDomain" else d, "-"], 15)
        if rc != 0 or not out:
            return job, None
        try:
            pl = plistlib.loads(out.encode("utf-8", "surrogateescape"))
        except Exception:
            return job, None
        return job, {k: _fingerprint(v) for k, v in pl.items()} if isinstance(pl, dict) else None

    snap = {}
    with ThreadPoolExecutor(16) as ex:
        for (host, d), keys in ex.map(one, jobs):
            if keys is not None:
                snap[("currentHost:" if host else "") + d] = keys
    return snap


def _diff(a, b):
    ch = []
    for dom in set(a) | set(b):
        ka, kb = a.get(dom, {}), b.get(dom, {})
        for k in set(ka) | set(kb):
            if ka.get(k) != kb.get(k):
                ch.append((dom, k, ka.get(k), kb.get(k)))
    return ch


def learn_pane(idx, label):
    """The Settings page to open for a learn label. Best: an App Intent whose
    title contains the label ('Update Tap to click') names its settings bundle
    (…settings-intents.trackpad), which names the pane. Otherwise the top pane
    from find. (A plain find tied Mouse and Trackpad on 'tap to click' and
    opened Mouse, 2026-09-26.)"""
    ln = norm(label)
    panes = {r["id"]: r for r in idx["records"] if r["kind"] == "system.pane" and not r.get("x_anchor")}
    for r in idx["records"]:
        if r["kind"] == "system.intent" and ln and ln in norm(r["outcome"]):
            seg = norm(r["x_bundle"].rsplit(".", 1)[-1])
            if f"system.pane.{seg}" in panes:
                return panes[f"system.pane.{seg}"]
    q = label.lower()
    toks = content_tokens(q.split())
    best = sorted((s, r["id"], r) for r in idx["records"] if r["kind"] == "system.pane"
                  for s in [score(r, q, norm(q), toks)] if s is not None)
    return best[0][2] if best else None


def cmd_learn(args):
    os.makedirs(LEARN_DIR, exist_ok=True)
    cur = os.path.join(LEARN_DIR, "current.json")
    sub = args[0] if args else None
    if sub == "start":
        label = " ".join(args[1:]).strip()
        if not label:
            die(2, "REFUSED learn start needs a label: what you are about to change, e.g. "
                   "`hilt learn start show battery percentage`", {"verdict": "REFUSED", "why": "no-label"})
        t0 = time.time()
        pane = learn_pane(load(), label)
        if pane and os.environ.get("HILT_NO_OPEN") != "1":
            run_pane(pane)  # Mark: "you could of been a baller and opened that up to that page"
        s1 = learn_snapshot()
        time.sleep(3)
        s2 = learn_snapshot()
        volatile = sorted({f"{d}\t{k}" for d, k, _, _ in _diff(s1, s2)})
        json.dump({"label": label, "ts": int(time.time()), "os_build": load()["os"]["build"],
                   "snapshot": s2, "volatile": volatile}, open(cur, "w"))
        emit({"verdict": "OK", "label": label, "domains": len(s2), "volatile": len(volatile),
              "seconds": round(time.time() - t0, 1), "opened": pane and pane["id"]},
             f"OK learning '{label}': {len(s2)} domains snapshotted ({len(volatile)} keys moved on their own "
             f"in 3 s and will be ignored). "
             + (f"Opened {pane['outcome'][len('open '):]} — " if pane else "")
             + "flip ONE control, then run `hilt learn diff`.")
    if sub == "diff":
        try:
            st = json.load(open(cur))
        except (OSError, ValueError):
            die(2, "REFUSED no learning in progress — `hilt learn start <label>` first",
                {"verdict": "REFUSED", "why": "not-started"})
        now = learn_snapshot()
        vol = set(st["volatile"])
        idx = load()
        known = {(r["x_domain"], r["x_key"]): r["id"] for r in idx["records"] if r["kind"] == "system.setting"}
        cands, noise = [], []
        for dom, k, old, new in _diff(st["snapshot"], now):
            base = dom.split(":", 1)[-1]
            if f"{dom}\t{k}" in vol or k in LEARN_CHURN.get(base, ()) or LEARN_NOISY.search(k):
                noise.append(f"{dom} {k}")
                continue
            typ = (new or old or ["?"])[0]
            scalar = typ in ("boolean", "integer", "float", "string")
            if not scalar:  # dates, data, dictionaries: bookkeeping, not a toggle
                noise.append(f"{dom} {k}")
                continue
            dom_ = "NSGlobalDomain" if base == "NSGlobalDomain" else base
            c = {"domain": dom_, "key": k, "scope": "currentHost" if dom.startswith("currentHost:") else "user",
                 "type": typ, "before": old[1] if old else None, "after": new[1] if new else None,
                 "writable_by_hilt": scalar and not dom.startswith("currentHost:"),
                 "already_known_as": known.get((dom_, k)),
                 "reload": RELOAD_OWNER.get(base)}
            if c["writable_by_hilt"] and not c["already_known_as"]:
                slug = norm(re.sub(r"^com\.apple\.", "", base).split(".")[-1]) or "global"
                c["proposed_row"] = {"id": f"system.{slug}.{norm(k)[:40]}", "domain": dom_, "key": k,
                                     "type": "float" if typ == "float" else typ,
                                     **({"default": old[1]} if old else {}),
                                     "outcome": st["label"], "aliases": [st["label"].lower()],
                                     **({"reload": RELOAD_OWNER[base]} if base in RELOAD_OWNER else {})}
            if c.get("proposed_row") and not old:
                c["note"] = ("the key was ABSENT before the click: macOS's value-when-absent is not "
                             "observable here, so no `default` is proposed; flip the control back and "
                             "diff again, or read Apple's default, before adding the row")
            cands.append(c)
        cands.sort(key=lambda c: (not c["writable_by_hilt"], c["already_known_as"] is not None, c["domain"]))
        json.dump({"label": st["label"], "candidates": cands, "noise": noise},
                  open(os.path.join(LEARN_DIR, f"{int(time.time())}-candidates.json"), "w"), indent=1)
        st["after"] = now
        st["candidates"] = cands
        json.dump(st, open(cur, "w"))
        lines = [f"'{st['label']}': {len(cands)} candidate key(s), {len(noise)} noise key(s) ignored"]
        for c in cands:
            lines.append(f"  {c['domain']} {c['key']} [{c['type']}{', currentHost' if c['scope'] == 'currentHost' else ''}] "
                         f"{c['before']!r} → {c['after']!r}"
                         + (f"  already: {c['already_known_as']}" if c["already_known_as"] else "")
                         + ("" if c["writable_by_hilt"] else "  (not writable by hilt yet: "
                            + ("currentHost scope" if c["scope"] == "currentHost" else "non-scalar value") + ")"))
        if any(c.get("proposed_row") for c in cands):
            lines.append("  proposed probes/settings.json row(s) — review, then add; `hilt build` validates, "
                         "`tools/exercise-settings.py` proves:")
            lines += ["    " + json.dumps(c["proposed_row"]) + (f"\n      note: {c['note']}" if c.get("note") else "")
                      for c in cands if c.get("proposed_row")]
        if cands:
            lines.append("  CONFIRM: flip the control BACK, then `hilt learn confirm` — only keys that return "
                         "to their old value are the control (background writes do not flip back)")
        if not cands:
            lines.append("  nothing changed in defaults: this control is stored elsewhere (TCC, a daemon, "
                         "networksetup, admin-only) — it stays a pane, or needs a native path")
        emit({"verdict": "OK" if cands else "NONE", "label": st["label"], "candidates": cands,
              "noise": len(noise)}, "\n".join(lines))
    if sub == "confirm":
        try:
            st = json.load(open(cur))
            cands = st["candidates"]
        except (OSError, ValueError, KeyError):
            die(2, "REFUSED nothing to confirm — `hilt learn start`, flip, `hilt learn diff` first",
                {"verdict": "REFUSED", "why": "not-diffed"})
        back = learn_snapshot()
        confirmed, stayed = [], []
        for c in cands:
            dom = ("currentHost:" if c["scope"] == "currentHost" else "") + c["domain"]
            now_v = (back.get(dom) or {}).get(c["key"])
            then_v = (st["snapshot"].get(dom) or {}).get(c["key"])
            (confirmed if now_v == then_v else stayed).append(c)
        rows = [c["proposed_row"] for c in confirmed if c.get("proposed_row")]
        lines = [f"'{st['label']}': {len(confirmed)} key(s) CONFIRMED (flipped back), {len(stayed)} discarded "
                 "(background writes)"]
        lines += [f"  {c['domain']} {c['key']} [{c['type']}] {c['before']!r} ⇄ {c['after']!r}"
                  + (f"  already: {c['already_known_as']}" if c["already_known_as"] else "") for c in confirmed]
        if rows:
            lines.append("  proposed probes/settings.json row(s): the before-value is macOS's current state; "
                         "review the id/outcome, add, `hilt build`, `tools/exercise-settings.py`:")
            lines += ["    " + json.dumps(r) for r in rows]
        os.replace(cur, os.path.join(LEARN_DIR, f"{int(time.time())}-confirmed.json"))
        emit({"verdict": "CONFIRMED" if confirmed else "NONE", "label": st["label"], "confirmed": confirmed,
              "discarded": len(stayed), "proposed_rows": rows}, "\n".join(lines))
    die(2, "REFUSED learn: `hilt learn start <label>`, flip one control, `hilt learn diff`, flip it back, "
           "`hilt learn confirm`",
        {"verdict": "REFUSED", "why": "bad-args"})


VOCAB_CHARS = 450  # default share; vlab's whole --context line is <= ~700 chars incl. ~15 agent names (#vlab 82)
USER_APP_ROOTS = ("/Applications/", os.path.expanduser("~/Applications/"))


def cmd_vocab(args):
    """Terms an ASR is likely to mishear, for vlab's initial-prompt bias
    (`vlab listen --context "$(hilt vocab)"`). Only words a general English
    model gets wrong earn a slot: names of the user's own apps, then the
    acronyms/jargon hilt's records answer to. Text mode prints ONE budgeted,
    comma-separated line; --json also returns the full ranked list."""
    idx = load()
    apps, jargon = [], []
    for r in idx["records"]:
        # User-installed apps, menu-bar ones included (Zil is LSUIElement):
        # their names are what a general model mishears.
        if r["kind"] == "application.launch" and \
                any(p.startswith(USER_APP_ROOTS) for p in r.get("x_paths", [])):
            apps.append(r["outcome"][len("open "):])
        if r["kind"] in ("system.state", "system.cli") or r.get("x_anchor", "").startswith("Services_"):
            for a in r.get("x_aliases", []):
                for w in a.split():
                    if 2 <= len(w) <= 5 and w.isalpha() and w not in STOPWORDS:
                        jargon.append(w)
    acr = {"ssh", "sshd", "smb", "vnc", "ard", "tcc", "dns", "dhcp", "usb", "arp", "cups", "rssi",
           "ip", "lan", "nat", "afp", "usb4"}
    jargon = [w.upper() if w in acr else w for w in dict.fromkeys(jargon) if w in acr]
    # RANK by how likely ASR is to mishear it (vlab #82: the line shares whisper's ~224-token
    # tail-kept prompt with ~15 agent names, so what gets cut must be what matters least).
    # Acronyms first; then names NOT in macOS's own dictionary (/usr/share/dict/words:
    # cmux, Ghostty, iTerm, Bitwarden); ordinary English words last (Messages, Pages,
    # Numbers need no bias). Alphabetical order used to cut Warp and Zil first.
    try:
        common = {w.strip().lower() for w in open("/usr/share/dict/words")}
    except OSError:
        common = set()
    def known(w):  # web2 has no plurals: "messages" -> "message"
        w = w.lower()
        return w in common or (w.endswith("s") and w[:-1] in common)
    def rank(t):
        if t.isupper():
            return (0, t)
        plain = all(known(w) for w in re.findall(r"[A-Za-z]+", t))
        return (2 if plain else 1, t.lower())
    # a name nobody says: web-app titles ("Starfield — A browser space game…"), helpers
    # ("Claude Code URL Handler") — more than 3 words, over 24 chars, or a dash separator
    sayable = lambda t: len(t) <= 24 and len(t.split()) <= 3 and "—" not in t and " - " not in t
    terms = sorted(dict.fromkeys(t for t in apps + jargon if sayable(t)), key=rank)
    try:
        budget = int(args[0]) if args else VOCAB_CHARS
    except ValueError:
        die(2, "REFUSED vocab takes an optional character budget, e.g. `hilt vocab 450`",
            {"verdict": "REFUSED", "why": "bad-args"})
    if budget < 20:
        die(2, "REFUSED vocab budget below 20 chars is empty", {"verdict": "REFUSED", "why": "out-of-range"})
    line, used = [], 0
    for t in terms:
        if used + len(t) + 2 > budget:
            continue  # a shorter, lower-ranked term may still fit
        line.append(t)
        used += len(t) + 2
    text = ", ".join(line)
    emit({"verdict": "OK", "context": text, "terms": terms, "shown": len(line), "total": len(terms),
          "budget_chars": budget, "chars": len(text)}, text)


def cmd_contract(_):
    emit({"verdict": "OK", "contract": HILT_CONTRACT, "version": HILT_VERSION,
          "python": sys.version.split()[0], "interpreter": sys.executable,
          "source_root": source_root()[0]},
         f"hilt contract {HILT_CONTRACT} · version {HILT_VERSION} · python {sys.version.split()[0]}")


VERBS = {"build": cmd_build, "orient": cmd_orient, "coverage": cmd_coverage, "find": cmd_find,
         "describe": cmd_describe, "run": cmd_run, "owners": cmd_owners, "traps": cmd_traps,
         "contract": cmd_contract, "permissions": cmd_permissions, "vocab": cmd_vocab, "inventory": cmd_inventory,
         "setup": cmd_setup, "learn": cmd_learn}


def main():
    global JSON
    argv = sys.argv[1:]
    head, tail = (argv[:argv.index("--")], argv[argv.index("--") + 1:]) if "--" in argv else (argv, [])
    OPTS.update(a for a in head if a in FLAGS)
    global CONFIRM_TOKEN
    for a in head:
        if a.startswith("--confirm="):
            CONFIRM_TOKEN = a[len("--confirm="):]
            OPTS.add("--confirm")
    head = [a for a in head if not a.startswith("--confirm=")]
    JSON = "--json" in OPTS
    # An unknown --flag before `--` is refused, never searched for: a contract-3
    # hilt read `find --criteria open slack` as the query "--criteria open
    # slack" and answered NONE, which a caller took for an answer (#zil 9).
    unknown = [a for a in head if a.startswith("--") and a not in FLAGS and a != "--help"]
    if unknown:
        die(2, f"REFUSED unknown option(s) {' '.join(unknown)} — this hilt speaks contract "
               f"{HILT_CONTRACT}; options: {' '.join(FLAGS)} (--confirm=<token>). Put `--` before a query that "
               "starts with dashes.", {"verdict": "REFUSED", "why": "unknown-option",
                                       "options": unknown, "contract": HILT_CONTRACT})
    argv = [a for a in head if a not in FLAGS] + tail
    if not argv or argv[0] in ("-h", "--help", "help"):
        print(__doc__.strip() + "\n\nverbs: " + " · ".join(VERBS))
        sys.exit(0)
    if argv[0] not in VERBS:
        die(2, f"UNKNOWN verb {argv[0]} — verbs: {', '.join(VERBS)}",
            {"verdict": "UNKNOWN", "verb": argv[0]})
    VERBS[argv[0]](argv[1:])


if __name__ == "__main__":
    main()
