"""Vault location — the one walk-up, replacing six drifted copies.

Sentinel: a directory holding ``Agent/config.json`` (or the legacy
``Alexandria/config.json``). Deliberately NOT ``AGENTS.md`` — the operating
manual leaves the vault under the de-vault plan (docs/DEVAULT.md step 5), while
Config stays, so the marker must be Config (docs/V3-P1-VAULT-CORE.md).

Resolution order: explicit argument → ``$VAULT_DIR`` → walk up from ``start``
(default: cwd). No silent fallback: the drifted originals fell back to
script-relative dirs or cwd, which is meaningless (and write-dangerous) for an
app-side library — a miss raises ``VaultNotFoundError`` instead.
"""
import os
from pathlib import Path


class VaultNotFoundError(RuntimeError):
    """No vault at/above the requested location (or the override isn't one)."""


def is_vault(path) -> bool:
    """True if ``path`` is a vault root (holds the Config marker)."""
    p = Path(path)
    return (p / "Agent" / "config.json").is_file() or (p / "Alexandria" / "config.json").is_file()


def locate_vault(explicit=None, start=None) -> Path:
    """Resolve the vault root. ``explicit`` (e.g. a ``--vault`` flag) wins, then
    ``$VAULT_DIR``, then a walk up from ``start``/cwd to the first directory that
    passes :func:`is_vault`. Overrides are validated, not trusted — pointing at a
    non-vault raises rather than letting a caller read (or worse, write) an
    arbitrary tree."""
    for label, cand in (("--vault", explicit), ("$VAULT_DIR", os.environ.get("VAULT_DIR"))):
        if cand:
            p = Path(cand).expanduser().resolve()
            if is_vault(p):
                return p
            raise VaultNotFoundError(f"{label} points at {p}, which has no Agent/config.json")
    cur = Path(start).resolve() if start else Path.cwd().resolve()
    for p in (cur, *cur.parents):
        if is_vault(p):
            return p
    raise VaultNotFoundError(f"no vault found at or above {cur}")
