Skip to content

memory.code_context

memory.code_context

Code-graph query and code ↔ memory tether helpers for the memory MCP server.

This module is the analysis substrate behind :func:memory.server.codebase's action dispatcher. It mirrors :mod:memory.retrieval: pure functions that take the live objects they operate on (the kglite code graph, a dulwich repo, the repo root, and — for tethers — a pre-collected list of memory entries) and return plain dicts, so the dispatcher in server.py stays thin and every function here is importable and mockable from tests.

It holds three things the design (documents/260720_code-memory-tethers-design.md) calls for:

  • Structure queriesblast (reverse dependency BFS), callers / callees (1-hop CALLS edges carrying call_lines), and the imports neighborhood, all with built-asset hygiene and depth/node caps.
  • Code ↔ memory tethers — the "touched" invert (per entry pin path@sha, diff the pin commit against its FIRST PARENT for that path, map changed line ranges onto kglite symbol ranges), the rolling tip, and the append-only provenance chain. Anchor identity is a qualified_name resolved against the live graph at query time; unsupported languages degrade to FILE anchors.
  • Health — a graded, located driver list (god object, coupling, cycle, churn, dead code) built from degree-style centrality over the code graph.

Every payload is decision-shaped: ranked, capped, with file:line and a next hint naming the follow-on call.

Tether soundness (the crux). A pin's first-parent diff is only trusted as the entry's edit (changed) for a single-parent commit that actually touched the path; merge commits (>1 parent) and the root commit (no parent) are attached as referenced (their first-parent diff does not represent a single edit), and a pin whose sha no longer resolves is referenced with degraded=True. Because a clean-file pin falls back to HEAD — a real user commit whose diff is unrelated to the entry — each chain entry also carries a provenance (memory for the isolated single-parent [memory] commit :func:_git_auto_commit creates for a dirty pin, else other); the rolling tip prefers a memory-provenance changed entry over an other one, so a clean-file HEAD fallback can never hijack the tip away from a genuine memory edit. (Genuine non-memory edits — reconstructed pins at historical user commits, or a hand-written pin — remain changed, since their diff really is the edit.)

Known limitations (documented, not fixed here):

  • Rename / move. The tether keys on qualified_name against the live graph, so a rename strands the old chain (reads as a new symbol). The FILE- level chain is always returned when the anchor's file resolves, so provenance is never fully lost. (The related line-shift mislabel — a later edit shifting a symbol's lines away from its pin-commit hunk ranges — is FIXED for reparseable languages: :func:_historical_symbol_span resolves the symbol's span at the pin commit; non-Python languages fall back to the live span.)
  • Unsupported languages by name. A bare symbol name in a language kglite does not parse (e.g. Julia .jl) has no graph node; :func:resolve_anchor falls back to a bounded source scan and, when a UNIQUE file defines the name, returns a file-level anchor (else absent with a hint). Passing the file path directly is always the unambiguous route.

is_built_asset

is_built_asset(path: str | None) -> bool

True when path lives under a built/generated asset directory.

Segment-based (not substring) so that a legitimate redistribute/ module is not mistaken for dist/.

Source code in memory/code_context.py
def is_built_asset(path: str | None) -> bool:
    """True when ``path`` lives under a built/generated asset directory.

    Segment-based (not substring) so that a legitimate ``redistribute/`` module
    is not mistaken for ``dist/``.
    """
    if not path:
        return False
    return any(seg in _BUILT_ASSET_SEGMENTS for seg in _norm(path).split("/"))

nested_repo_prefixes

nested_repo_prefixes(root: str | PathLike[str] | None) -> tuple[str, ...]

Repo-relative prefixes of nested git repositories under root.

Any directory OTHER than root that contains its own .git is a nested/vendored repository or clone — its files are not part of this repo's source and must never enter the code graph. The motivating case: eval sandboxes that clone the whole repo into dev/runs/.../clone-*/ (each a full working copy with its own .git), which otherwise swamp the graph with thousands of duplicate File nodes and wedge the dashboard. The kglite builder walks the raw working tree and honors neither .gitignore nor nested-repo boundaries, so the exclusion is applied downstream as a graph filter (see :func:in_nested_repo).

Each returned prefix is forward-slashed and ends in / so a plain path.startswith(prefix) test excludes the entire subtree. The walk prunes built-asset and dot directories for speed and stops descending as soon as a nested repo is found (so the clones themselves are never traversed).

Source code in memory/code_context.py
def nested_repo_prefixes(root: str | os.PathLike[str] | None) -> tuple[str, ...]:
    """Repo-relative prefixes of nested git repositories under ``root``.

    Any directory OTHER than ``root`` that contains its own ``.git`` is a
    nested/vendored repository or clone — its files are not part of *this* repo's
    source and must never enter the code graph. The motivating case: eval
    sandboxes that clone the whole repo into ``dev/runs/.../clone-*/`` (each a
    full working copy with its own ``.git``), which otherwise swamp the graph with
    thousands of duplicate ``File`` nodes and wedge the dashboard. The kglite
    builder walks the raw working tree and honors neither ``.gitignore`` nor
    nested-repo boundaries, so the exclusion is applied downstream as a graph
    filter (see :func:`in_nested_repo`).

    Each returned prefix is forward-slashed and ends in ``/`` so a plain
    ``path.startswith(prefix)`` test excludes the entire subtree. The walk prunes
    built-asset and dot directories for speed and stops descending as soon as a
    nested repo is found (so the clones themselves are never traversed).
    """
    if not root:
        return ()
    root_path = Path(root)
    prefixes: list[str] = []
    for dirpath, dirnames, _files in os.walk(root_path, topdown=True):
        rel = os.path.relpath(dirpath, root_path)
        # A non-root directory holding its own .git IS a nested repo: record it
        # and prune (don't walk the clone's thousands of files).
        if rel != "." and ".git" in dirnames:
            prefixes.append(rel.replace(os.sep, "/").rstrip("/") + "/")
            dirnames[:] = []
            continue
        # Everywhere else, skip built-asset and dot dirs (including the repo's own
        # .git) to keep the scan cheap and aligned with the graph's exclusions.
        dirnames[:] = [
            d for d in dirnames
            if d not in _BUILT_ASSET_SEGMENTS and not d.startswith(".")
        ]
    return tuple(prefixes)

in_nested_repo

in_nested_repo(path: str | None, prefixes: tuple[str, ...]) -> bool

True when path lives inside one of prefixes (a nested repo/clone).

Companion to :func:nested_repo_prefixes; prefixes are computed once per graph build and reused across the file/symbol filter loops.

Source code in memory/code_context.py
def in_nested_repo(path: str | None, prefixes: tuple[str, ...]) -> bool:
    """True when ``path`` lives inside one of ``prefixes`` (a nested repo/clone).

    Companion to :func:`nested_repo_prefixes`; ``prefixes`` are computed once per
    graph build and reused across the file/symbol filter loops.
    """
    if not path or not prefixes:
        return False
    p = _norm(path)
    return any(p.startswith(pre) for pre in prefixes)

resolve_anchor

resolve_anchor(graph: Any, query: str = '', path: str = '', root: Path | None = None) -> dict

Resolve a user anchor to a stable code-graph identity.

An anchor is either a symbol (keyed by qualified_name) or a file (keyed by repo-relative path). Resolution is deliberately forgiving — query may be a full angelo.memory.server._pin_files qualified name, a trailing server._pin_files fragment, a bare _pin_files name, or a file path. Unsupported / unparsed files (e.g. Julia .jl) resolve to a FILE anchor so provenance is never lost.

When a bare-name symbol query matches no graph node AND is not path-ish, and a repo root is supplied, a BOUNDED source-file scan (:func:_scan_source_files_for_definition) is the last resort: it recovers unparsed-language symbols (e.g. Julia) that kglite never nodalized. A unique defining file yields a FILE anchor (with resolved_via='name-scan'); zero or several matches keep absent but add a hint (and, for several, the usual candidate_count / ambiguity_note).

Returns a dict with kind in {"symbol", "file", "absent"} plus, when resolved, qualified_name / name / type / file_path / line_number / end_line. kind == "absent" means the anchor could not be located in the current graph (e.g. a deleted symbol) — callers keep the historical chain but flag the anchor missing.

Source code in memory/code_context.py
def resolve_anchor(graph: Any, query: str = "", path: str = "", root: Path | None = None) -> dict:
    """Resolve a user anchor to a stable code-graph identity.

    An anchor is either a **symbol** (keyed by ``qualified_name``) or a **file**
    (keyed by repo-relative ``path``). Resolution is deliberately forgiving —
    ``query`` may be a full ``angelo.memory.server._pin_files`` qualified name, a
    trailing ``server._pin_files`` fragment, a bare ``_pin_files`` name, or a file
    path. Unsupported / unparsed files (e.g. Julia ``.jl``) resolve to a FILE
    anchor so provenance is never lost.

    When a bare-name symbol query matches no graph node AND is not path-ish, and
    a repo ``root`` is supplied, a BOUNDED source-file scan
    (:func:`_scan_source_files_for_definition`) is the last resort: it recovers
    unparsed-language symbols (e.g. Julia) that kglite never nodalized. A unique
    defining file yields a FILE anchor (with ``resolved_via='name-scan'``); zero
    or several matches keep ``absent`` but add a hint (and, for several, the
    usual ``candidate_count`` / ``ambiguity_note``).

    Returns a dict with ``kind`` in ``{"symbol", "file", "absent"}`` plus, when
    resolved, ``qualified_name`` / ``name`` / ``type`` / ``file_path`` /
    ``line_number`` / ``end_line``. ``kind == "absent"`` means the anchor could
    not be located in the current graph (e.g. a deleted symbol) — callers keep
    the historical chain but flag the anchor missing.
    """
    q = (query or "").strip()
    p = _norm(path).strip()

    # Explicit file path, or a query that is clearly a path and matches a File.
    if p:
        return _resolve_file(graph, p)
    if q and ("/" in q or q.rsplit(".", 1)[-1] in _FILE_EXTS):
        fa = _resolve_file(graph, q)
        if fa["kind"] != "absent":
            return fa

    if not q:
        return {"kind": "absent"}

    # Symbol resolution. Try the most specific matcher first and resolve
    # DETERMINISTICALLY: an exact qualified_name is unambiguous; the fuzzier
    # ENDS-WITH / name / title fallbacks are ordered by (file_path, line_number)
    # and, when more than one non-built candidate remains, still pick the first
    # but surface the ambiguity (candidate_count + note) rather than silently
    # returning an arbitrary row.
    for clause, param, exact in (
        ("n.qualified_name = $q", q, True),
        ("n.qualified_name ENDS WITH $q", "." + q, False),
        ("n.name = $q", q, False),
        ("n.title = $q", q, False),
    ):
        rows = _rows(
            graph,
            f"MATCH (n) WHERE n.type IN $types AND {clause} "
            "RETURN n.qualified_name AS qualified_name, n.name AS name, "
            "n.type AS type, n.file_path AS file_path, "
            "n.line_number AS line_number, n.end_line AS end_line "
            "ORDER BY n.file_path, n.line_number LIMIT 50",
            {"types": list(CODE_NODE_TYPES), "q": param},
        )
        rows = [r for r in rows if not is_built_asset(r.get("file_path"))]
        if not rows:
            continue
        best = dict(rows[0])
        best["kind"] = "symbol"
        best["file_path"] = _norm(best.get("file_path") or "")
        if len(rows) > 1:
            best["candidate_count"] = len(rows)
            best["candidates"] = [
                f"{_norm(r.get('file_path') or '')}:{r.get('line_number')}" for r in rows[:5]
            ]
            kind_desc = "qualified_name collisions" if exact else "symbols"
            best["ambiguity_note"] = (
                f"{len(rows)} {kind_desc} match {q!r}; resolved deterministically to "
                f"{best['file_path']}:{best.get('line_number')}. Pass a fuller "
                "qualified_name or path= to disambiguate."
            )
        return best

    # Nothing matched as a symbol; if it looks path-ish, report an absent file.
    if "/" in q or q.rsplit(".", 1)[-1] in _FILE_EXTS:
        return {"kind": "file", "file_path": q, "absent": True}

    # Last resort for an otherwise-absent bare NAME: scan source files for a
    # definition so unparsed-language symbols (e.g. Julia) stay reachable by
    # name. Only a UNIQUE defining file promotes to a (present) file anchor.
    if root is not None and _IDENT_RE.match(q):
        matches, complete = _scan_source_files_for_definition(root, q)
        if len(matches) == 1 and complete:
            fa = _resolve_file(graph, matches[0])
            fa["query"] = q
            fa["resolved_via"] = "name-scan"
            fa.setdefault("note", (
                f"{q!r} is not a parsed graph symbol; resolved by source scan to "
                f"a unique defining file {matches[0]} (unparsed-language fallback)."
            ))
            return fa
        if len(matches) > 1:
            return {
                "kind": "absent",
                "query": q,
                "candidate_count": len(matches),
                "candidates": matches[:5],
                "ambiguity_note": (
                    f"{len(matches)} files define {q!r}; pass path= (or a fuller "
                    "qualified_name) to disambiguate."
                ),
                "hint": "action='lookup' to search by name, or pass path= to anchor a file.",
            }
        if len(matches) == 1 and not complete:
            # A single hit but the walk stopped at the file cap: a second
            # definition could lie beyond it, so this is INCONCLUSIVE, not a
            # unique anchor. Stay absent (never a wrong anchor) with a note.
            return {
                "kind": "absent",
                "query": q,
                "note": (
                    f"a bounded source scan found one candidate definition of "
                    f"{q!r} ({matches[0]}) but stopped at the {_SCAN_MAX_FILES}-file "
                    "cap before confirming uniqueness; pass path= to anchor it."
                ),
                "hint": "pass path= to anchor a file, or action='lookup' to search by name.",
            }

    return {"kind": "absent", "query": q}

callers

callers(graph: Any, anchor: dict, limit: int = DEFAULT_HOP_LIMIT) -> dict

Decision-shaped 1-hop callers of a (specific) symbol/file anchor.

Source code in memory/code_context.py
def callers(graph: Any, anchor: dict, limit: int = DEFAULT_HOP_LIMIT) -> dict:
    """Decision-shaped 1-hop callers of a (specific) symbol/file anchor."""
    seeds = _anchor_seeds(graph, anchor)
    rows = _calls_neighbors(graph, seeds, "callers")[:limit]
    return {
        "anchor": _anchor_label(anchor),
        "callers": [_hop_row(r) for r in rows],
        "count": len(rows),
        "next": "call codebase(action=\"blast\") for the transitive impact, or "
                "codebase(action=\"context\") for why this exists",
    }

callees

callees(graph: Any, anchor: dict, limit: int = DEFAULT_HOP_LIMIT) -> dict

Decision-shaped 1-hop callees of a (specific) symbol/file anchor.

Source code in memory/code_context.py
def callees(graph: Any, anchor: dict, limit: int = DEFAULT_HOP_LIMIT) -> dict:
    """Decision-shaped 1-hop callees of a (specific) symbol/file anchor."""
    seeds = _anchor_seeds(graph, anchor)
    rows = _calls_neighbors(graph, seeds, "callees")[:limit]
    return {
        "anchor": _anchor_label(anchor),
        "callees": [_hop_row(r) for r in rows],
        "count": len(rows),
        "next": "call codebase(action=\"context\") on a callee to see why it exists",
    }

with_ambiguity

with_ambiguity(payload: dict, anchor: dict) -> dict

Propagate an ambiguous anchor's disambiguation hints into payload.

:func:resolve_anchor records candidate_count / ambiguity_note when a bare name resolved deterministically but non-uniquely. This surfaces them on the tool payload so the user sees the resolution was ambiguous. Keys are added only when present, so unambiguous results stay uncluttered.

Source code in memory/code_context.py
def with_ambiguity(payload: dict, anchor: dict) -> dict:
    """Propagate an ambiguous anchor's disambiguation hints into ``payload``.

    :func:`resolve_anchor` records ``candidate_count`` / ``ambiguity_note`` when a
    bare name resolved deterministically but non-uniquely. This surfaces them on
    the tool payload so the user sees the resolution was ambiguous. Keys are added
    only when present, so unambiguous results stay uncluttered.
    """
    if isinstance(payload, dict):
        for k in ("ambiguity_note", "candidate_count"):
            if anchor.get(k) is not None and k not in payload:
                payload[k] = anchor[k]
    return payload

blast

blast(graph: Any, anchor: dict, depth: int = DEFAULT_BLAST_DEPTH, node_cap: int = DEFAULT_BLAST_NODES) -> dict

Reverse-dependency BFS: what breaks if this anchor changes.

Unions two dependency channels with SEPARATE budgets so the precise signal is never evicted by the coarse one:

  • reverse CALLS (precise) — a breadth-first walk from the anchor's specific seed node(s); distance-1 callers are graded breaks, deeper ones maybe (relation="calls"). This channel is filled FIRST, in distance order, up to the full node_cap — so transitive call-path breakage always survives the cap.
  • reverse IMPORTS (coarse) — files that import the anchor's package, appended AFTER calls as distance-1 file-level dependents graded maybe (relation="imports"), up to a SMALL separate cap (min(node_cap - calls, DEFAULT_IMPORT_CAP)). Package-grained (kglite's only import granularity), so it is a coarse superset that must not crowd out real callers on a hot package.

Built assets are excluded throughout; cycle-safety is via visited.

Source code in memory/code_context.py
def blast(
    graph: Any,
    anchor: dict,
    depth: int = DEFAULT_BLAST_DEPTH,
    node_cap: int = DEFAULT_BLAST_NODES,
) -> dict:
    """Reverse-dependency BFS: what breaks if this anchor changes.

    Unions two dependency channels with SEPARATE budgets so the precise signal is
    never evicted by the coarse one:

    * **reverse ``CALLS``** (precise) — a breadth-first walk from the anchor's
      specific seed node(s); distance-1 callers are graded ``breaks``, deeper ones
      ``maybe`` (``relation="calls"``). This channel is filled FIRST, in distance
      order, up to the full ``node_cap`` — so transitive call-path breakage always
      survives the cap.
    * **reverse ``IMPORTS``** (coarse) — files that import the anchor's package,
      appended AFTER calls as distance-1 file-level dependents graded ``maybe``
      (``relation="imports"``), up to a SMALL separate cap
      (``min(node_cap - calls, DEFAULT_IMPORT_CAP)``). Package-grained (kglite's
      only import granularity), so it is a coarse superset that must not crowd out
      real callers on a hot package.

    Built assets are excluded throughout; cycle-safety is via ``visited``.
    """
    depth = max(1, min(int(depth or DEFAULT_BLAST_DEPTH), MAX_BLAST_DEPTH))
    node_cap = max(1, int(node_cap or DEFAULT_BLAST_NODES))

    seeds = _anchor_seeds(graph, anchor)
    call_items: dict[str, dict] = {}
    frontier: set[tuple[str, str | None]] = set(seeds)
    visited: set[tuple[str, str | None]] = set(seeds)
    calls_truncated = False

    # Channel 1: reverse CALLS BFS (precise, distance-graded) — fills node_cap first.
    for dist in range(1, depth + 1):
        if not frontier or len(call_items) >= node_cap:
            calls_truncated = calls_truncated or bool(frontier)
            break
        # Sort each level so truncation within a distance is deterministic.
        rows = sorted(
            _calls_neighbors(graph, list(frontier), "callers"),
            key=lambda r: (r.get("file_path") or "", r.get("qualified_name") or ""),
        )
        next_frontier: set[tuple[str, str | None]] = set()
        for r in rows:
            qn, fp = r.get("qualified_name"), r.get("file_path")
            node = (qn, fp)
            key = f"{qn}\x00{fp}"
            if node in visited or key in call_items:
                continue
            if len(call_items) >= node_cap:
                calls_truncated = True
                break
            call_items[key] = {
                "qualified_name": qn,
                "name": r.get("name"),
                "type": r.get("type"),
                "file": fp,
                "line": r.get("line_number"),
                "distance": dist,
                "severity": "breaks" if dist == 1 else "maybe",
                "relation": "calls",
                "via": r.get("via"),
            }
            next_frontier.add(node)
        visited |= next_frontier
        frontier = next_frontier

    ranked_calls = sorted(
        call_items.values(),
        key=lambda x: (x["distance"], x["file"] or "", x.get("qualified_name") or ""),
    )

    # Channel 2: reverse IMPORTS (coarse) — appended within its OWN small budget.
    # Skip any file already surfaced as a precise caller: its coarse import edge
    # would be a redundant, lower-signal duplicate of the call row.
    call_files = {x["file"] for x in ranked_calls if x.get("file")}
    import_budget = max(0, min(node_cap - len(ranked_calls), DEFAULT_IMPORT_CAP))
    import_deps = [d for d in _import_dependents(graph, anchor) if d["file"] not in call_files]
    imports_truncated = len(import_deps) > import_budget
    import_items = [
        {
            "qualified_name": None,
            "name": Path(dep["file"]).name,
            "type": "File",
            "file": dep["file"],
            "line": None,
            "distance": 1,
            "severity": "maybe",
            "relation": "imports",
            "via": dep["package"],
        }
        for dep in import_deps[:import_budget]
    ]

    ranked = ranked_calls + import_items
    import_count = len(import_items)
    tests_affected = sorted({x["file"] for x in ranked if _is_test_path(x.get("file"))})
    return {
        "anchor": _anchor_label(anchor),
        "anchor_kind": anchor.get("kind"),
        "depth": depth,
        "impacted": ranked,
        "impacted_count": len(ranked),
        "import_dependents": import_count,
        "capped": calls_truncated or imports_truncated,
        "tests_affected": tests_affected,
        "summary": _blast_summary(anchor, ranked, tests_affected, import_count),
        "next": "call codebase(action=\"context\") to see why these exist; "
                "record(..., files=...) after editing so the tethers advance",
    }

import_neighborhood

import_neighborhood(graph: Any, anchor: dict, limit: int = DEFAULT_HOP_LIMIT) -> dict

File/module import neighborhood: what this file imports and who imports it.

kglite records IMPORTS as File -> Module at a coarse (top-level) module grain, so the reverse ("who imports this") is resolved by the anchor file's top-level package name rather than the exact module — useful, but package-level, not symbol-level.

Source code in memory/code_context.py
def import_neighborhood(graph: Any, anchor: dict, limit: int = DEFAULT_HOP_LIMIT) -> dict:
    """File/module import neighborhood: what this file imports and who imports it.

    kglite records ``IMPORTS`` as ``File -> Module`` at a coarse (top-level)
    module grain, so the reverse ("who imports this") is resolved by the anchor
    file's top-level package name rather than the exact module — useful, but
    package-level, not symbol-level.
    """
    # Both symbol and file anchors carry a defining file_path; pivot to it.
    fpath = _norm(anchor.get("file_path") or "")
    if not fpath:
        return {"anchor": _anchor_label(anchor), "error": "imports needs a file or module anchor"}

    outgoing = _rows(
        graph,
        "MATCH (f:File)-[:IMPORTS]->(m:Module) WHERE f.path = $p "
        "RETURN DISTINCT m.name AS module ORDER BY module",
        {"p": fpath},
    )
    out_modules = [r["module"] for r in outgoing if r.get("module")][:limit]

    # Reverse: files importing this file's top-level package (coarse; shared with blast).
    incoming = [d["file"] for d in _import_dependents(graph, anchor)][:limit]

    return {
        "anchor": fpath,
        "imports": out_modules,
        "imported_by": incoming,
        "next": "call codebase(action=\"blast\") for the call-level impact",
    }

latest_code_commit

latest_code_commit(root: Path | None) -> str | None

SHA of the newest commit that changed a tracked path OUTSIDE .memory/.

This is the code_head used to key the code graph and the per-anchor tether cache — deliberately NOT plain git HEAD. The memory MCP server auto-commits .memory/ bookkeeping frequently (often several times an hour), and every such commit moves HEAD without changing a single line of code. Keying on raw HEAD would invalidate the entire code cache on each of those commits, so a large tree's tether warm could never outrun the churn (the code-lens overlay would perpetually re-warm and never light up). Anchoring to the last code commit makes the cache stable across the bookkeeping commits while still invalidating the instant real code lands.

Implemented with git log -1 over ':(top)' minus every .memory/ tree: the (top) magic anchors the pathspecs at the repo root so the result is independent of the process cwd, ':(top)' matches all files, ':(exclude,top).memory' drops the ROOT .memory/, and ':(exclude,glob)**/.memory/**' drops any NESTED .memory/ (e.g. the per-clone memory stores under dev/runs/.../evalmem-*/.memory/ that the study runners commit constantly) — those are all memory bookkeeping, not code. Without the nested exclude, a commit touching only a nested .memory/ file would advance code_head, needlessly triggering the whole-tree code-graph reparse (and, pre-fix, orphaning the tether cache). A mixed commit that also touched real code still counts. Both the dashboard route and the agent-facing codebase(context) path call this so they share one cache key. Falls back to plain HEAD when the pathspec query fails or the repo has no non-memory commit yet, and returns None when there is no repo/root.

Source code in memory/code_context.py
def latest_code_commit(root: Path | None) -> str | None:
    """SHA of the newest commit that changed a tracked path OUTSIDE ``.memory/``.

    This is the ``code_head`` used to key the code graph and the per-anchor
    tether cache — deliberately NOT plain ``git HEAD``. The memory MCP server
    auto-commits ``.memory/`` bookkeeping frequently (often several times an
    hour), and every such commit moves ``HEAD`` without changing a single line
    of code. Keying on raw ``HEAD`` would invalidate the entire code cache on
    each of those commits, so a large tree's tether warm could never outrun the
    churn (the code-lens overlay would perpetually re-warm and never light up).
    Anchoring to the last *code* commit makes the cache stable across the
    bookkeeping commits while still invalidating the instant real code lands.

    Implemented with ``git log -1`` over ``':(top)'`` minus every ``.memory/``
    tree: the ``(top)`` magic anchors the pathspecs at the repo root so the result
    is independent of the process cwd, ``':(top)'`` matches all files,
    ``':(exclude,top).memory'`` drops the ROOT ``.memory/``, and
    ``':(exclude,glob)**/.memory/**'`` drops any NESTED ``.memory/`` (e.g. the
    per-clone memory stores under ``dev/runs/.../evalmem-*/.memory/`` that the
    study runners commit constantly) — those are all memory bookkeeping, not code.
    Without the nested exclude, a commit touching only a nested ``.memory/`` file
    would advance ``code_head``, needlessly triggering the whole-tree code-graph
    reparse (and, pre-fix, orphaning the tether cache). A mixed commit that also
    touched real code still counts. Both the dashboard route and the agent-facing
    ``codebase(context)`` path call this so they share one cache key. Falls back to
    plain ``HEAD`` when the pathspec query fails or the repo has no non-memory
    commit yet, and returns ``None`` when there is no repo/root.
    """
    if root is None:
        return None
    try:
        proc = subprocess.run(
            ("git", "log", "-1", "--format=%H", "HEAD", "--",
             ":(top)", ":(exclude,top).memory", ":(exclude,glob)**/.memory/**"),
            cwd=str(root),
            check=False,
            capture_output=True,
            text=True,
        )
        sha = proc.stdout.strip()
        if proc.returncode == 0 and sha:
            return sha
    except Exception:
        pass
    # Fallback: plain HEAD (fresh repo, or a repo whose entire history is under
    # .memory/ — degenerate, but better than no key at all).
    try:
        proc = subprocess.run(
            ("git", "rev-parse", "HEAD"),
            cwd=str(root),
            check=False,
            capture_output=True,
            text=True,
        )
        sha = proc.stdout.strip()
        if proc.returncode == 0 and sha:
            return sha
    except Exception:
        pass
    return None

build_anchor_context

build_anchor_context(graph: Any, root: Path | None, anchor: dict, entries: Sequence[dict], caches: dict | None = None) -> dict

Derive the tip + provenance chain for a single anchor.

caches (optional) is a pass-level cache bundle — a dict with sub-dicts meta / diff / blob (git-op memoization keyed by (path, sha)) and span (the historical-span cache). When a caller warms MANY anchors in one pass (:func:collect_tethers / :func:backfill_tethers) it shares one bundle across every anchor, so the per-(path, sha) git subprocesses (_commit_meta, _run_git_diff_ranges, git show) run ONCE for a file rather than once per symbol — the difference between a snappy warm and one that re-diffs a 200-symbol file 200 times. When caches is None (the standalone single-anchor agent context call) the caches are per-call and the span cache is loaded from and saved to disk here exactly as before; when a span cache is SHARED in, the caller owns its one-shot persistence.

entries is the pre-collected set of memory entries carrying pins (each a dict with id / title / type / created_at / files); the caller gathers them (already excluding discarded/merged entries) so this function stays free of the memory graph. For each entry that pins the anchor's file the relation is derived conservatively:

  • a single-parent pin commit that touched the path is diffed against its first parent. A symbol anchor is changed when a changed range overlaps its span AS IT WAS AT THE PIN COMMIT — resolved by reparsing the file blob at that sha (:func:_historical_symbol_span), so a later edit that shifts the symbol's lines does not mislabel a genuine changed as referenced. Only Python is reparsed; other languages fall back to the live line_number..end_line span. A file anchor is changed when the diff is non-empty; otherwise referenced.
  • a merge commit (>1 parent) or the root commit (no parent) is attached as referenced and NOT diffed — a single first-parent diff does not faithfully represent one edit there.
  • a pin whose sha no longer resolves (gc/rebase/amend), or a single-parent pin whose first-parent diff cannot be computed (git error, or a missing parent object in a shallow/partial clone), is referenced with degraded=True — distinct from both a genuine reference and a genuinely empty (clean) diff.

Each entry also carries provenance: memory for the isolated single-parent [memory] commit :func:_git_auto_commit makes for a dirty pin, else other. This is used only by :func:_select_tip, which prefers a memory-provenance changed entry, so a clean-file HEAD fallback (an unrelated user commit whose diff happens to touch the path) can never hijack the tip from a genuine memory edit.

The FILE-level chain is returned whenever the anchor's file resolves (so a symbol anchor still carries its file's history). The chain is append-only, ordered by created_at.

Source code in memory/code_context.py
def build_anchor_context(
    graph: Any,
    root: Path | None,
    anchor: dict,
    entries: Sequence[dict],
    caches: dict | None = None,
) -> dict:
    """Derive the tip + provenance chain for a single anchor.

    ``caches`` (optional) is a pass-level cache bundle — a dict with sub-dicts
    ``meta`` / ``diff`` / ``blob`` (git-op memoization keyed by ``(path, sha)``)
    and ``span`` (the historical-span cache). When a caller warms MANY anchors in
    one pass (:func:`collect_tethers` / :func:`backfill_tethers`) it shares one
    bundle across every anchor, so the per-``(path, sha)`` git subprocesses
    (``_commit_meta``, ``_run_git_diff_ranges``, ``git show``) run ONCE for a file
    rather than once per symbol — the difference between a snappy warm and one
    that re-diffs a 200-symbol file 200 times. When ``caches`` is ``None`` (the
    standalone single-anchor agent ``context`` call) the caches are per-call and
    the span cache is loaded from and saved to disk here exactly as before; when a
    ``span`` cache is SHARED in, the caller owns its one-shot persistence.

    ``entries`` is the pre-collected set of memory entries carrying pins (each a
    dict with ``id`` / ``title`` / ``type`` / ``created_at`` / ``files``); the
    caller gathers them (already excluding discarded/merged entries) so this
    function stays free of the memory graph. For each entry that pins the
    anchor's file the relation is derived conservatively:

    * a **single-parent** pin commit that touched the path is diffed against its
      first parent. A **symbol** anchor is ``changed`` when a changed range
      overlaps its span AS IT WAS AT THE PIN COMMIT — resolved by reparsing the
      file blob at that sha (:func:`_historical_symbol_span`), so a later edit
      that shifts the symbol's lines does not mislabel a genuine ``changed`` as
      ``referenced``. Only Python is reparsed; other languages fall back to the
      live ``line_number..end_line`` span. A **file** anchor is ``changed`` when
      the diff is non-empty; otherwise ``referenced``.
    * a **merge** commit (>1 parent) or the **root** commit (no parent) is
      attached as ``referenced`` and NOT diffed — a single first-parent diff does
      not faithfully represent one edit there.
    * a pin whose sha no longer resolves (gc/rebase/amend), or a single-parent pin
      whose first-parent diff cannot be computed (git error, or a missing parent
      object in a shallow/partial clone), is ``referenced`` with ``degraded=True``
      — distinct from both a genuine reference and a genuinely empty (clean) diff.

    Each entry also carries ``provenance``: ``memory`` for the isolated
    single-parent ``[memory]`` commit :func:`_git_auto_commit` makes for a dirty
    pin, else ``other``. This is used only by :func:`_select_tip`, which prefers a
    ``memory``-provenance ``changed`` entry, so a clean-file HEAD fallback (an
    unrelated user commit whose diff happens to touch the path) can never hijack
    the tip from a genuine memory edit.

    The FILE-level chain is returned whenever the anchor's file resolves (so a
    symbol anchor still carries its file's history). The chain is append-only,
    ordered by ``created_at``.
    """
    fpath = _norm(anchor.get("file_path") or "")
    is_symbol = anchor.get("kind") == "symbol"
    lo = anchor.get("line_number") if is_symbol else None
    hi = anchor.get("end_line") if is_symbol else None
    qname = anchor.get("qualified_name") or ""

    chain: list[dict] = []
    # Pass-level cache bundle. Shared across anchors when a warm pass hands one in
    # (so a file's git ops resolve once, not once per symbol); per-call otherwise.
    _caches = caches if caches is not None else {}
    # Git-op memoization keyed by (path, sha): commit metadata, the parent-diff,
    # and the historical blob. Entries sharing a pin commit (common for memory's
    # isolated commits) — and all symbols of a file — resolve each once.
    meta_cache: dict = _caches.setdefault("meta", {})
    diff_cache: dict = _caches.setdefault("diff", {})
    blob_cache: dict = _caches.setdefault("blob", {})
    # Parsed-AST cache per (sha, path): the single biggest cold-warm win — a file
    # parses ONCE, every symbol in it walks the shared tree (see _historical_symbol_span).
    tree_cache: dict = _caches.setdefault("tree", {})
    # Historical-span cache (per (sha, path, qualified_name)). A blob at a sha —
    # and the pin's diff — are immutable, so a resolved span never needs
    # invalidation. When SHARED in, the caller loaded it once and persists it once
    # (``owns_span`` False); standalone, we load here and save below. Only symbol
    # anchors consult it (files have no span).
    owns_span = "span" not in _caches
    span_cache: dict = (
        (_load_span_cache() if is_symbol else {}) if owns_span else _caches["span"]
    )
    span_cache_len0 = len(span_cache)
    if fpath and root is not None:
        # (entry, sha) pins on THIS file. A shared warm pass supplies a prebuilt
        # {file: [(entry, sha)]} map (built once, O(entries)); a standalone call
        # builds just this file's slice inline. Either form yields the FIRST sha
        # per (entry, file) in entry order — identical to the historical
        # one-pin-per-entry ``break``. This removes the per-anchor O(entries)
        # rescan that dominated a large-tree warm (turning it O(anchors × entries)
        # even with the git ops cached).
        file_pins = _caches.get("file_pins")
        pins_here = file_pins.get(fpath, ()) if file_pins is not None else _file_pins_for(entries, fpath)
        for entry, sha in pins_here:
            path = fpath  # by construction: this entry pinned fpath at this sha
            key = f"{path}\x00{sha}"
            if key not in meta_cache:
                meta_cache[key] = _commit_meta(root, sha)
            meta = meta_cache[key]

            degraded = False
            if meta is None:
                relation = "referenced"  # sha unresolvable (gc/rebase/amend)
                degraded = True
            elif meta[0] != 1:
                relation = "referenced"  # merge (>1 parent) or root (0) — never diff
            else:
                if key not in diff_cache:
                    diff_cache[key] = _run_git_diff_ranges(root, sha, path)
                ranges = diff_cache[key]
                if ranges is None:
                    # Single-parent, but the diff could not be computed (git
                    # error, or a missing parent object in a shallow/partial
                    # clone) — distinct from a genuinely empty diff.
                    relation = "referenced"
                    degraded = True
                elif is_symbol:
                    # Symbol: intersect the pin-commit hunks against the
                    # symbol's span AT THAT SHA (line-shift safe). Additions
                    # intersect inclusively; pure-deletion gaps use the
                    # interior rule (a trailing-boundary delete must NOT mark
                    # the symbol changed).
                    hspan = _cached_historical_span(
                        root, sha, path, qname, span_cache,
                        changed_ranges=ranges, blob_cache=blob_cache,
                        tree_cache=tree_cache,
                    )
                    if hspan is _SPAN_READ_FAILED:
                        # A Python blob that could not be read or parsed at the
                        # pin sha: the historical span is unknown, so trusting
                        # the live span would silently risk the line-shift
                        # mislabel FU-1 fixes. Flag degraded (mirrors the
                        # git-error path).
                        relation = "referenced"
                        degraded = True
                    elif hspan is _SPAN_SYMBOL_ABSENT:
                        # The symbol did NOT exist under this qualified_name at
                        # the pin sha, so the pin cannot have edited it — a
                        # CONFIDENT ``referenced`` (NOT degraded). Do NOT
                        # intersect the live span: a live span that merely
                        # overlaps the pin's hunks would be a FALSE ``changed``
                        # (the FU-1 P1a bug).
                        relation = "referenced"
                    elif hspan is None:
                        # NON-Python file: no reparse, fall back to the live
                        # span (documented, non-degraded, unchanged behavior).
                        relation = "changed" if _symbol_touched(ranges, lo, hi) else "referenced"
                    else:
                        slo, shi = hspan
                        relation = "changed" if _symbol_touched(ranges, slo, shi) else "referenced"
                else:
                    # File: ANY add-or-delete hunk is a genuine edit.
                    relation = "changed" if ranges else "referenced"

            item = {
                "id": entry.get("id"),
                "title": entry.get("title"),
                "type": entry.get("type"),
                "created_at": entry.get("created_at"),
                "relation": relation,
                "provenance": "memory" if _is_memory_edit(meta) else "other",
            }
            if degraded:
                item["degraded"] = True
            chain.append(item)

    # Persist newly-computed historical spans (best-effort; cache is disposable).
    # Only when WE own the cache — a shared span cache is persisted once by the
    # warm-pass caller, not on every anchor.
    if owns_span and is_symbol and len(span_cache) != span_cache_len0:
        try:
            atomic_write(_span_cache_path(), json.dumps(span_cache, default=str))
        except Exception:
            pass

    chain.sort(key=lambda e: e.get("created_at") or "")
    tip = _select_tip(chain)
    out: dict = {
        "anchor": _anchor_label(anchor),
        "anchor_kind": anchor.get("kind"),
        "file": fpath or anchor.get("file_path"),
        "tip": tip,
        "chain": chain,
        "chain_count": len(chain),
        "next": "call codebase(action=\"blast\") for what breaks; pass "
                "expand_synapse=true to reach ZK canon via synapse(action=\"connections\")",
    }
    if anchor.get("absent") or anchor.get("kind") == "absent":
        out["anchor_absent"] = True
        out["note"] = (
            "anchor not found in the live graph (deleted, unparsed, or unknown "
            "symbol); chain is historical"
        )
    return out

cached_anchor_context

cached_anchor_context(graph: Any, root: Path | None, anchor: dict, entries: Sequence[dict], code_head: str | None, pin_index: dict[str, str] | None = None, caches: dict | None = None, file_tokens: dict[str, str] | None = None) -> dict

:func:build_anchor_context with a lazy per-anchor disk cache.

The cache lives under .angelo/code_tethers/ and is keyed by the anchor's OWN file token (its blob sha at code_head — see :func:_anchor_cache_disk_key) plus its OWN relevant pins (:func:_anchor_pin_signature) — NOT the global memory signature and NOT the global code_head. This keeps the canonical edit→record→context loop warm across unrelated memory writes AND across code commits to OTHER files, while still invalidating the instant a pin on this file changes, an entry is discarded, or THIS file's content moves. A read never touches the git working tree (the cache dir is under the gitignored .angelo/); any cache error degrades to a direct recompute — the cache is disposable.

A :func:build_anchor_context that raises is caught and a degraded result (:func:_degraded_anchor_payload) is returned TRANSIENTLY — never propagated, but also never written to the durable disk cache. So one pathological anchor can neither abort a warm nor wedge the dashboard in refining, yet a TRANSIENT failure (git index.lock contention, an interrupted subprocess, an OOM reparse) retries on the very next call rather than freezing an empty chain under the durable (code_head + pins) key until HEAD/pins move. A permanently-failing anchor is bounded instead by the route's _TETHER_ATTEMPTS settle cap. Only a SUCCESSFUL build is cached (and invalidated when the anchor's pins or code HEAD move).

pin_index is forwarded to the cache-key computation for an O(1) per-anchor signature; the resulting key is byte-identical to the un-indexed path, so a warm write and a later read agree whether or not the index was supplied. caches is the pass-level git/span cache bundle forwarded to :func:build_anchor_context on a cold build (shared by a warm pass so a file's git ops resolve once, not once per symbol).

Source code in memory/code_context.py
def cached_anchor_context(
    graph: Any,
    root: Path | None,
    anchor: dict,
    entries: Sequence[dict],
    code_head: str | None,
    pin_index: dict[str, str] | None = None,
    caches: dict | None = None,
    file_tokens: dict[str, str] | None = None,
) -> dict:
    """:func:`build_anchor_context` with a lazy per-anchor disk cache.

    The cache lives under ``.angelo/code_tethers/`` and is keyed by the anchor's
    OWN file token (its blob sha at ``code_head`` — see :func:`_anchor_cache_disk_key`)
    plus its OWN relevant pins (:func:`_anchor_pin_signature`) — NOT the global
    memory signature and NOT the global ``code_head``. This keeps the canonical
    edit→record→context loop warm across unrelated memory writes AND across code
    commits to OTHER files, while still invalidating the instant a pin on this
    file changes, an entry is discarded, or THIS file's content moves. A read
    never touches the git working tree (the cache dir is under the gitignored
    ``.angelo/``); any cache error degrades to a direct recompute — the cache is
    disposable.

    A :func:`build_anchor_context` that raises is caught and a degraded result
    (:func:`_degraded_anchor_payload`) is returned TRANSIENTLY — never propagated,
    but also never written to the durable disk cache. So one pathological anchor
    can neither abort a warm nor wedge the dashboard in ``refining``, yet a
    TRANSIENT failure (git ``index.lock`` contention, an interrupted subprocess,
    an OOM reparse) retries on the very next call rather than freezing an empty
    chain under the durable ``(code_head + pins)`` key until HEAD/pins move. A
    permanently-failing anchor is bounded instead by the route's
    ``_TETHER_ATTEMPTS`` settle cap. Only a SUCCESSFUL build is cached (and
    invalidated when the anchor's pins or code HEAD move).

    ``pin_index`` is forwarded to the cache-key computation for an O(1) per-anchor
    signature; the resulting key is byte-identical to the un-indexed path, so a
    warm write and a later read agree whether or not the index was supplied.
    ``caches`` is the pass-level git/span cache bundle forwarded to
    :func:`build_anchor_context` on a cold build (shared by a warm pass so a
    file's git ops resolve once, not once per symbol).
    """
    cached = _peek_anchor_context(
        anchor, entries, code_head, pin_index, root, file_tokens
    )
    if cached is not None:
        return cached

    try:
        payload = build_anchor_context(graph, root, anchor, entries, caches=caches)
    except Exception:
        # Transient degradation: return an empty-chain payload but do NOT persist
        # it, so the next call (dashboard poll or agent context) retries the build.
        return _degraded_anchor_payload(anchor)
    cache_key = _anchor_cache_disk_key(
        anchor, entries, code_head, pin_index, root, file_tokens
    )
    path = _tether_cache_dir() / f"{_anchor_cache_key(anchor)}.json"
    try:
        atomic_write(path, json.dumps({"_key": cache_key, "payload": payload}, default=str))
    except Exception:
        pass
    return payload

backfill_tethers

backfill_tethers(graph: Any, root: Path | None, entries: Sequence[dict], code_head: str | None) -> dict

Optional one-shot: warm the tether cache for every pinned anchor.

Walks every entry pin once, inverts each to touched anchors, and writes the per-anchor cache entries. Not required for correctness — lazy :func:cached_anchor_context covers cold anchors — but pays the invert cost up front for a large existing tree. Returns a small progress summary.

Source code in memory/code_context.py
def backfill_tethers(
    graph: Any,
    root: Path | None,
    entries: Sequence[dict],
    code_head: str | None,
) -> dict:
    """Optional one-shot: warm the tether cache for every pinned anchor.

    Walks every entry pin once, inverts each to touched anchors, and writes the
    per-anchor cache entries. Not required for correctness — lazy
    :func:`cached_anchor_context` covers cold anchors — but pays the invert cost
    up front for a large existing tree. Returns a small progress summary.
    """
    # ``pinned_files`` counts every distinct pinned path (built assets included)
    # for the progress summary; ``_pinned_anchors`` does the built-asset-filtered
    # file→symbol expansion the warm loop iterates.
    pinned_paths: set[str] = set()
    for entry in entries:
        for path, _sha in _parse_pins(entry.get("files", "")):
            pinned_paths.add(path)

    # Precompute the per-file pin signatures once so each anchor's cache-key
    # lookup is O(1) rather than an O(entries) rescan (see _build_pin_index).
    pin_index = _build_pin_index(entries)
    # Snapshot every tracked file's blob sha at code_head once, so per-anchor
    # cache keys are scoped to their own file's content (see _head_blob_tokens).
    file_tokens = _head_blob_tokens(root, code_head)
    # One shared cache bundle across the whole pass so a file's git ops
    # (_commit_meta / _run_git_diff_ranges / git show) resolve once, not once per
    # symbol; the span cache is loaded once here and persisted once below.
    caches = _new_warm_caches(entries)
    # Prime every distinct (path, sha) git op in parallel up front, so the anchor
    # loop below is pure cache-hit Python (turns a serial git-subprocess floor of
    # minutes into ~seconds on a large tree).
    _prewarm_git_caches(root, caches)
    warmed = 0
    for anchor in _pinned_anchors(graph, entries):
        cached_anchor_context(
            graph, root, anchor, entries, code_head, pin_index, caches, file_tokens
        )
        warmed += 1
    _persist_warm_span_cache(caches)
    return {"pinned_files": len(pinned_paths), "anchors_warmed": warmed}

tether_record

tether_record(anchor: dict, payload: dict) -> dict | None

The compact overlay dict for one anchor, or None if it has no tether.

Distills a :func:build_anchor_context payload down to what the code-lens overlay needs::

{"anchor": <qualified_name | file_path::name | file_path>,
 "kind": "symbol" | "file",
 "file_path": <repo-relative path>,
 "tip": <the _select_tip result or None>,
 "tip_created_at": <the tip entry's created_at, for latest-activity ranking>,
 "chain_count": int,
 "relation": <the anchor's governing (tip) relation, or None>,
 "degraded": bool}

The anchor id is the overlay identity (:func:_overlay_anchor_id) so it matches the backdrop node id even for a null-qualified_name symbol.

Returns None for an empty chain (the anchor renders grey from the backdrop, not the lit overlay). Factored out so both :func:collect_tethers and the dashboard's single-pass cold-start build the record identically.

Source code in memory/code_context.py
def tether_record(anchor: dict, payload: dict) -> dict | None:
    """The compact overlay dict for one anchor, or ``None`` if it has no tether.

    Distills a :func:`build_anchor_context` payload down to what the code-lens
    overlay needs::

        {"anchor": <qualified_name | file_path::name | file_path>,
         "kind": "symbol" | "file",
         "file_path": <repo-relative path>,
         "tip": <the _select_tip result or None>,
         "tip_created_at": <the tip entry's created_at, for latest-activity ranking>,
         "chain_count": int,
         "relation": <the anchor's governing (tip) relation, or None>,
         "degraded": bool}

    The ``anchor`` id is the overlay identity (:func:`_overlay_anchor_id`) so it
    matches the backdrop node id even for a null-``qualified_name`` symbol.

    Returns ``None`` for an empty chain (the anchor renders grey from the
    backdrop, not the lit overlay). Factored out so both :func:`collect_tethers`
    and the dashboard's single-pass cold-start build the record identically.
    """
    chain = payload.get("chain") or []
    if not chain:
        return None

    tip = payload.get("tip")
    # The tip dict (from _select_tip) omits created_at; recover it from the
    # matching chain entry so the caller can rank the single latest activity.
    tip_created_at = None
    if tip:
        for c in chain:
            if c.get("id") == tip.get("id"):
                tip_created_at = c.get("created_at")
                break

    return {
        "anchor": _overlay_anchor_id(anchor),
        "kind": anchor.get("kind"),
        "file_path": _norm(anchor.get("file_path") or ""),
        "tip": tip,
        "tip_created_at": tip_created_at,
        "chain_count": payload.get("chain_count", len(chain)),
        "relation": (tip or {}).get("relation"),
        "degraded": bool(payload.get("anchor_absent"))
        or any(c.get("degraded") for c in chain),
    }

peek_anchors_parallel

peek_anchors_parallel(anchors: Sequence[dict], entries: Sequence[dict], code_head: str | None, pin_index: dict[str, str] | None = None, root: Path | None = None, file_tokens: dict[str, str] | None = None, *, workers: int | None = None) -> list[tuple[dict, dict | None]]

Peek every anchor's disk cache in parallel; return [(anchor, payload)].

:func:_peek_anchor_context is READ-ONLY (reads one cache file, validates its key against pin_index) with no shared mutable state, so it is safe to fan out across a thread pool. A cache miss is a cheap stat; a hit reads+parses a small JSON file — and a warm reload peeks THOUSANDS of hits, the dominant cost of a fresh process's first overlay pass. Parallelizing the reads cuts that wall time by roughly the pool size (I/O-bound on a synced filesystem). Order is preserved so callers can zip results back against anchors. Never raises per anchor: a peek that errors is reported as a miss (None).

Source code in memory/code_context.py
def peek_anchors_parallel(
    anchors: Sequence[dict],
    entries: Sequence[dict],
    code_head: str | None,
    pin_index: dict[str, str] | None = None,
    root: Path | None = None,
    file_tokens: dict[str, str] | None = None,
    *,
    workers: int | None = None,
) -> list[tuple[dict, dict | None]]:
    """Peek every anchor's disk cache in parallel; return ``[(anchor, payload)]``.

    :func:`_peek_anchor_context` is READ-ONLY (reads one cache file, validates its
    key against ``pin_index``) with no shared mutable state, so it is safe to fan
    out across a thread pool. A cache *miss* is a cheap stat; a *hit* reads+parses
    a small JSON file — and a warm reload peeks THOUSANDS of hits, the dominant
    cost of a fresh process's first overlay pass. Parallelizing the reads cuts that
    wall time by roughly the pool size (I/O-bound on a synced filesystem). Order is
    preserved so callers can zip results back against ``anchors``. Never raises per
    anchor: a peek that errors is reported as a miss (``None``).
    """
    if not anchors:
        return []

    def _one(anchor: dict) -> tuple[dict, dict | None]:
        try:
            return anchor, _peek_anchor_context(
                anchor, entries, code_head, pin_index, root, file_tokens
            )
        except Exception:
            return anchor, None

    n = workers if workers is not None else min(12, len(anchors))
    n = max(1, n)
    if n == 1 or len(anchors) == 1:
        return [_one(a) for a in anchors]
    with ThreadPoolExecutor(max_workers=n) as pool:
        return list(pool.map(_one, anchors))

collect_tethers

collect_tethers(graph: Any, root: Path | None, entries: Sequence[dict], code_head: str | None, *, cache_only: bool = False) -> list[dict]

Returning variant of :func:backfill_tethers: the tether overlay data.

Where :func:backfill_tethers only warms the cache, this returns a :func:tether_record for every pinned anchor that carries at least one tether. The per-anchor path is IDENTICAL to the agent-facing context action (:func:cached_anchor_context → :func:build_anchor_context → :func:_select_tip), so the tip logic never diverges.

cache_only (cold-start): peek the per-anchor disk cache and include ONLY already-warm anchors, never computing a cold invert. The dashboard serves this partial overlay instantly while a background thread warms the full set.

Two-phase for a snappy WARM (reload) path: phase 1 peeks every anchor's disk cache IN PARALLEL (:func:peek_anchors_parallel) — reads are I/O-bound and independent, so a fully-warm cache (a fresh process re-reading thousands of files) resolves in a fraction of the old serial time. phase 2 builds only the cold misses serially (they mutate the shared parse/span caches, so they are not parallelized), priming the git caches once if there is anything to build. In the all-warm case phase 2 is empty; in the cold case phase-1 peeks are cheap misses and the build path is unchanged.

Each anchor is wrapped independently so one raising anchor can never abort the whole warm (leaving the rest of the invert — and the dashboard's refining settle — permanently stuck). cached_anchor_context degrades a raising anchor transiently (returned, not cached, so it retries next call); this guard also covers _peek_anchor_context / tether_record.

Source code in memory/code_context.py
def collect_tethers(
    graph: Any,
    root: Path | None,
    entries: Sequence[dict],
    code_head: str | None,
    *,
    cache_only: bool = False,
) -> list[dict]:
    """Returning variant of :func:`backfill_tethers`: the tether overlay data.

    Where :func:`backfill_tethers` only warms the cache, this returns a
    :func:`tether_record` for every pinned anchor that carries **at least one**
    tether. The per-anchor path is IDENTICAL to the agent-facing ``context``
    action (:func:`cached_anchor_context` → :func:`build_anchor_context` →
    :func:`_select_tip`), so the tip logic never diverges.

    ``cache_only`` (cold-start): peek the per-anchor disk cache and include ONLY
    already-warm anchors, never computing a cold invert. The dashboard serves this
    partial overlay instantly while a background thread warms the full set.

    Two-phase for a snappy WARM (reload) path: phase 1 peeks every anchor's disk
    cache IN PARALLEL (:func:`peek_anchors_parallel`) — reads are I/O-bound and
    independent, so a fully-warm cache (a fresh process re-reading thousands of
    files) resolves in a fraction of the old serial time. phase 2 builds only the
    cold misses serially (they mutate the shared parse/span caches, so they are not
    parallelized), priming the git caches once if there is anything to build. In
    the all-warm case phase 2 is empty; in the cold case phase-1 peeks are cheap
    misses and the build path is unchanged.

    Each anchor is wrapped independently so one raising anchor can never abort the
    whole warm (leaving the rest of the invert — and the dashboard's ``refining``
    settle — permanently stuck). ``cached_anchor_context`` degrades a raising
    anchor transiently (returned, not cached, so it retries next call); this guard
    also covers ``_peek_anchor_context`` / ``tether_record``.
    """
    # Precompute the per-file pin signatures once so each anchor's cache-key
    # lookup is O(1) rather than an O(entries) rescan (see _build_pin_index).
    pin_index = _build_pin_index(entries)
    # Snapshot every tracked file's blob sha at code_head ONCE (one git ls-tree),
    # so per-anchor cache keys are scoped to their own file's content — a commit
    # to one file leaves every other file's anchors warm (see _head_blob_tokens).
    file_tokens = _head_blob_tokens(root, code_head)
    anchors = _pinned_anchors(graph, entries)

    # Phase 1 — parallel peek (read-only, disk-I/O bound). Serves the all-warm
    # reload path fast; in the cold case these are cheap misses.
    peeked = peek_anchors_parallel(
        anchors, entries, code_head, pin_index, root, file_tokens
    )

    if cache_only:
        out: list[dict] = []
        for anchor, payload in peeked:
            if payload is None:
                continue
            try:
                record = tether_record(anchor, payload)
            except Exception:
                continue
            if record is not None:
                out.append(record)
        return out

    # Phase 2 — build the cold misses serially (they mutate the shared parse/span
    # caches). Prime the git caches ONCE, scoped to JUST the miss files — so an
    # almost-warm reload with a few cold stragglers primes their files only, not
    # the whole tree (keeps warm-again ~seconds, not tens of seconds).
    miss_files = {
        anchor.get("file_path") for anchor, payload in peeked if payload is None
    }
    caches = None
    if miss_files:
        caches = _new_warm_caches(entries)
        _prewarm_git_caches(root, caches, only_files=miss_files)

    out = []
    for anchor, payload in peeked:
        try:
            if payload is None:
                payload = cached_anchor_context(
                    graph, root, anchor, entries, code_head, pin_index, caches,
                    file_tokens,
                )
            record = tether_record(anchor, payload)
        except Exception:
            continue
        if record is not None:
            out.append(record)
    if caches is not None:
        _persist_warm_span_cache(caches)
    return out

ownership

ownership(root: Path | None, anchor: dict, *, top: int = 10) -> dict

Who authored an anchor: git-blame attribution over its live line span.

For a symbol anchor, blames its [line_number, end_line] range in its file; for a file anchor (or a symbol lacking a line span), blames the whole file. Contributions are aggregated by author into owners — line count and the author's most-recent commit (sha + date) within the blamed span — ranked by lines desc. The memory-mcp bot is filtered out (by its memory@local email — unspoofable — with the author name as a secondary check) so ownership reflects real authoring contributors.

Coordinate consistency (FU-4 fix): the -L range comes from the LIVE anchor, which kglite parses from the WORKING TREE, so blame is run against the working tree too (no HEAD argument). Pinning to HEAD while ranging with working-tree line numbers would silently misattribute lines whenever the tree is dirty and the symbol shifted; blaming the working copy keeps the line numbers aligned with the anchor. On a clean tree this is identical to blaming HEAD; on a dirty tree, locally-modified lines attribute to git's all-zero Not Committed Yet boundary. Those uncommitted lines are NOT committed authorship, so they are excluded from owners (an informational uncommitted_lines count is surfaced instead) — owners contains only real committers, and the memory-mcp bot is likewise filtered.

Robust by construction: the file path handed to git is the resolved anchor's file_path (never user free-text), git is invoked with an argv list (no shell), and the no-git / not-a-repo / unresolvable-file / empty-blame cases return an informative note rather than raising.

Source code in memory/code_context.py
def ownership(root: Path | None, anchor: dict, *, top: int = 10) -> dict:
    """Who authored an anchor: git-blame attribution over its live line span.

    For a **symbol** anchor, blames its ``[line_number, end_line]`` range in its
    file; for a **file** anchor (or a symbol lacking a line span), blames the
    whole file. Contributions are aggregated by author into ``owners`` — line
    count and the author's most-recent commit (``sha`` + date) within the blamed
    span — ranked by lines desc. The memory-mcp bot is filtered out (by its
    ``memory@local`` email — unspoofable — with the author name as a secondary
    check) so ownership reflects real authoring contributors.

    Coordinate consistency (FU-4 fix): the ``-L`` range comes from the LIVE anchor,
    which kglite parses from the WORKING TREE, so blame is run against the working
    tree too (no ``HEAD`` argument). Pinning to ``HEAD`` while ranging with
    working-tree line numbers would silently misattribute lines whenever the tree
    is dirty and the symbol shifted; blaming the working copy keeps the line
    numbers aligned with the anchor. On a clean tree this is identical to blaming
    ``HEAD``; on a dirty tree, locally-modified lines attribute to git's all-zero
    ``Not Committed Yet`` boundary. Those uncommitted lines are NOT committed
    authorship, so they are excluded from ``owners`` (an informational
    ``uncommitted_lines`` count is surfaced instead) — ``owners`` contains only
    real committers, and the memory-mcp bot is likewise filtered.

    Robust by construction: the file path handed to ``git`` is the resolved
    anchor's ``file_path`` (never user free-text), git is invoked with an argv
    list (no shell), and the no-git / not-a-repo / unresolvable-file / empty-blame
    cases return an informative ``note`` rather than raising.
    """
    fpath = _norm(anchor.get("file_path") or "")
    label = _anchor_label(anchor)
    base = {"anchor": label, "anchor_kind": anchor.get("kind"), "file": fpath, "owners": []}
    if root is None:
        return {**base, "note": "no git repository available for ownership"}
    if not fpath:
        return {**base, "note": "ownership needs a file or symbol anchor with a resolved file"}

    # Guard the file argument: it must be the resolved anchor's own path (a real
    # relative file under the repo root), never arbitrary user text.
    try:
        target = (root / fpath).resolve()
        target.relative_to(root.resolve())
    except (ValueError, OSError):
        return {**base, "note": f"anchor file {fpath!r} is outside the repository"}
    if not target.exists():
        return {**base, "note": f"anchor file {fpath!r} does not exist in the working tree"}

    argv = ["git", "blame", "--line-porcelain"]
    lo = anchor.get("line_number") if anchor.get("kind") == "symbol" else None
    hi = anchor.get("end_line") if anchor.get("kind") == "symbol" else None
    ranged = False
    if isinstance(lo, int) and lo > 0:
        hi_eff = hi if isinstance(hi, int) and hi >= lo else lo
        argv += ["-L", f"{lo},{hi_eff}"]
        ranged = True
    # No rev: blame the WORKING TREE so line numbers align with the live anchor's
    # (working-tree) range — see the docstring's coordinate-consistency note.
    argv += ["--", fpath]

    try:
        proc = subprocess.run(
            argv, cwd=str(root), check=False, capture_output=True, text=True
        )
    except Exception as e:
        return {**base, "note": f"git blame unavailable: {e}"}
    if proc.returncode != 0:
        return {**base, "note": "git blame failed (not a git repo, or file not tracked)"}

    stats = _parse_blame_porcelain(proc.stdout)
    # Working-tree blame lumps every locally-modified line under the boundary
    # pseudo-author; count them for an informational note but NEVER as an owner.
    uncommitted_lines = sum(
        rec["lines"]
        for author, rec in stats.items()
        if _is_uncommitted_boundary(author, rec.get("email", ""), rec.get("last_sha"))
    )
    owners = [
        {
            "author": author,
            "lines": rec["lines"],
            "last_commit": {
                "sha": (rec["last_sha"] or "")[:12] or None,
                "date": _epoch_to_date(rec["last_time"] if rec["last_time"] >= 0 else None),
            },
        }
        for author, rec in stats.items()
        if not _is_memory_bot_author(author, rec.get("email", ""))
        and not _is_uncommitted_boundary(author, rec.get("email", ""), rec.get("last_sha"))
    ]
    owners.sort(key=lambda o: (o["lines"], o["last_commit"]["date"] or ""), reverse=True)
    owners = owners[: max(1, int(top or 10))]

    out = {
        "anchor": label,
        "anchor_kind": anchor.get("kind"),
        "file": fpath,
        "scope": f"lines {lo}-{hi if hi else lo}" if ranged else "whole file",
        "owners": owners,
        "owner_count": len(owners),
        "next": "call codebase(action=\"context\") to see why this exists, or "
                "codebase(action=\"blast\") for what depends on it",
    }
    if uncommitted_lines:
        # Surface local churn without polluting `owners` — a hint that the blamed
        # span has uncommitted edits (they are excluded from authorship above).
        out["uncommitted_lines"] = uncommitted_lines
    if not owners:
        out["note"] = (
            "no human authorship attributed (blame empty, or only memory-mcp "
            "commits touch this span)"
        )
    return out

health

health(graph: Any, root: Path | None, *, per_signal: int = HEALTH_PER_SIGNAL) -> dict

Graded code-health report with located, actionable drivers.

Reuses degree-style centrality already latent in the code graph (method counts, call fan, import degree, call-cycle SCCs) plus git churn to surface five anti-pattern signals: god object, coupling, cycle, churn, dead code. Betweenness/pagerank over the full multi-hundred-thousand-node graph is deliberately avoided to keep the call sub-second; degree centrality captures the same anti-patterns cheaply.

Source code in memory/code_context.py
def health(graph: Any, root: Path | None, *, per_signal: int = HEALTH_PER_SIGNAL) -> dict:
    """Graded code-health report with located, actionable drivers.

    Reuses degree-style centrality already latent in the code graph (method
    counts, call fan, import degree, call-cycle SCCs) plus git churn to surface
    five anti-pattern signals: god object, coupling, cycle, churn, dead code.
    Betweenness/pagerank over the full multi-hundred-thousand-node graph is
    deliberately avoided to keep the call sub-second; degree centrality captures
    the same anti-patterns cheaply.
    """
    drivers: list[dict] = []
    drivers += _god_object_drivers(graph, per_signal)
    drivers += _coupling_drivers(graph, per_signal)
    drivers += _cycle_drivers(graph, per_signal)
    drivers += _churn_drivers(root, per_signal)
    drivers += _dead_code_drivers(graph, per_signal)

    grade = _grade(drivers)
    return {
        "grade": grade,
        "drivers": drivers,
        "driver_count": len(drivers),
        "next": "call codebase(action=\"blast\") on a driver symbol to size the "
                "risk, then codebase(action=\"context\") for its history",
    }