core_engine_classify.py 2.42 KB
"""05 §5.8 / U-035: path-based classification of whether a self-target
change touches "core engine" territory -- `.claude/agents/*.md` identity
files, Graph Engine scheduler/executor source (`src/*.py`), or 01-M's own
schema (`src/schema.py`, itself a `src/*.py` file so already covered).

Deliberately NOT the Validator's existing 3-perspective `judge_root_cause`
(root_cause_trace.py) -- that produces planning|coder|skill_defect from
content-level judgment about WHY a bug happened; this produces core_engine
from a purely mechanical WHERE-did-the-change-land rule, independent of
whether anything went wrong. The two are orthogonal and only combined at
the call site (scheduler.py), never merged into one function.

Scope note: `frontend/` is deliberately excluded (05 §5.8 names the identity
files + engine source + schema, not the console UI -- a frontend/app.js bug
is much lower blast radius and doesn't need blue-green). `supervisor/` IS
included -- Deploy Supervisor modifying its own isolation/rollback logic is
at least as self-referentially risky as the engine it's protecting.
"""

import posixpath

_CORE_ENGINE_PREFIXES = ("src/", "supervisor/", ".claude/agents/")


def classify_core_engine_change(changed_files):
    """changed_files: iterable of repo-relative paths (posix-style, as
    produced by `git diff --name-only` / `diff --git a/X b/Y` headers).
    Returns True if ANY path falls under a core-engine prefix."""
    for path in changed_files:
        normalized = posixpath.normpath(path.replace("\\", "/"))
        if normalized.startswith(_CORE_ENGINE_PREFIXES) or any(
            normalized == prefix.rstrip("/") for prefix in _CORE_ENGINE_PREFIXES
        ):
            return True
    return False


def parse_changed_files_from_diff(diff_text):
    """Extracts repo-relative changed file paths from unified `git diff`
    output (`diff --git a/X b/Y` header lines) -- avoids requiring a second
    git subprocess call when the diff text is already on hand (e.g. as the
    code_diff artifact's content)."""
    changed = []
    for line in (diff_text or "").splitlines():
        if line.startswith("diff --git a/"):
            rest = line[len("diff --git a/"):]
            # "<a-path> b/<b-path>" -- split on the last " b/" occurrence
            # since a path itself could theoretically contain " b/".
            marker = rest.rfind(" b/")
            if marker != -1:
                changed.append(rest[:marker])
    return changed