"""muse code stable — symbol stability leaderboard. The inverse of ``muse code hotspots``. Finds the symbols that have been unchanged the longest — your bedrock, the code you can safely build on. A function that hasn't needed modification across 50 commits is either perfectly written or perfectly scoped. Either way, it's stable. Build your architecture around stable symbols. Documentation file symbols (Markdown, TOML, YAML, JSON, plain text) are excluded by default because they almost never appear in structured-delta ops and would otherwise crowd out all code results. Pass ``--include-docs`` to include them. Import pseudo-symbols (``::import::*``) are excluded by default. Pass ``--include-imports`` to include them. Usage:: muse code stable muse code stable --top 20 muse code stable --kind function --language Python muse code stable --since v2.0.0 # stability window since a tag muse code stable --json # machine-readable for agents Output:: Symbol stability — top 10 most stable symbols Commits analysed: 302 1 muse/core/store.py::content_hash unchanged for 302 commits (since first commit) 2 muse/core/store.py::sha256_bytes unchanged for 287 commits 3 muse/core/repo.py::require_repo unchanged for 241 commits These are your bedrock. High stability = safe to build on. """ from __future__ import annotations import argparse import json import logging import pathlib import sys from muse.core.errors import ExitCode from muse.core.repo import read_repo_id, require_repo from muse.core.store import get_commit_snapshot_manifest, read_current_branch, resolve_commit_ref from muse.plugins.code._query import ( _SUFFIX_LANG, flat_symbol_ops, language_of, symbols_for_snapshot, walk_commits_bfs, ) from muse.core.validation import clamp_int, sanitize_display type _IntMap = dict[str, int] type _Filters = dict[str, str | int | bool | None] type _StrMap = dict[str, str] logger = logging.getLogger(__name__) _DEFAULT_TOP = 20 _DEFAULT_MAX_COMMITS = 10_000 # Language normalisation (case-insensitive --language matching). _LANG_CANONICAL: _StrMap = {lang.lower(): lang for lang in set(_SUFFIX_LANG.values())} # Languages to exclude by default: documentation formats whose symbols are # almost never touched by structured-delta ops and crowd out code results. _DOC_LANGUAGES: frozenset[str] = frozenset({ "Markdown", "Text", "TOML", "YAML", "JSON", "reStructuredText", }) def _normalise_language(lang: str) -> str: return _LANG_CANONICAL.get(lang.strip().lower(), lang.strip()) def register(subparsers: "argparse._SubParsersAction[argparse.ArgumentParser]") -> None: """Register the stable subcommand.""" parser = subparsers.add_parser( "stable", help="Show the symbols that have been unchanged the longest.", description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, ) parser.add_argument( "--top", "-n", type=int, default=_DEFAULT_TOP, metavar="N", help=f"Number of symbols to show (default: {_DEFAULT_TOP}).", ) parser.add_argument( "--kind", "-k", dest="kind_filter", default=None, metavar="KIND", help="Restrict to symbols of this kind (function, class, method, …).", ) parser.add_argument( "--language", "-l", dest="language_filter", default=None, metavar="LANG", help="Restrict to symbols from files of this language (case-insensitive).", ) parser.add_argument( "--since", dest="since_ref", default=None, metavar="REF", help=( "Only count commits reachable from HEAD back to this ref " "(tag, commit SHA, or branch). Useful for 'stable since v2.0'." ), ) parser.add_argument( "--max-commits", type=int, default=_DEFAULT_MAX_COMMITS, metavar="N", help=f"Maximum commits to scan (default: {_DEFAULT_MAX_COMMITS}).", ) parser.add_argument( "--include-imports", dest="include_imports", action="store_true", help="Include import pseudo-symbols (excluded by default).", ) parser.add_argument( "--include-docs", dest="include_docs", action="store_true", help=( "Include symbols from documentation files — Markdown, TOML, " "YAML, JSON, plain text (excluded by default)." ), ) parser.add_argument( "--json", dest="as_json", action="store_true", help="Emit results as JSON.", ) parser.set_defaults(func=run) def run(args: argparse.Namespace) -> None: """Show the symbols that have been unchanged the longest. ``muse code stable`` is the complement of ``muse code hotspots``. It identifies the bedrock of your codebase — the functions, classes, and methods that have been stable across the most commits. These are the symbols safest to build on: they haven't changed because they don't need to. They reveal your stable API surface. """ top: int = clamp_int(args.top, 1, 10000, 'top') kind_filter: str | None = args.kind_filter language_filter: str | None = args.language_filter since_ref: str | None = args.since_ref max_commits: int = clamp_int(args.max_commits, 1, 100000, 'max_commits') include_imports: bool = args.include_imports include_docs: bool = args.include_docs as_json: bool = args.as_json if top < 1: print("❌ --top must be >= 1.", file=sys.stderr) raise SystemExit(ExitCode.USER_ERROR) if max_commits < 1: print("❌ --max-commits must be >= 1.", file=sys.stderr) raise SystemExit(ExitCode.USER_ERROR) if language_filter is not None: language_filter = _normalise_language(language_filter) if kind_filter is not None: kind_filter = kind_filter.strip().lower() root = require_repo() repo_id = read_repo_id(root) branch = read_current_branch(root) head_commit = resolve_commit_ref(root, repo_id, branch, None) if head_commit is None: print("❌ No commits found.", file=sys.stderr) raise SystemExit(ExitCode.USER_ERROR) # Resolve optional --since boundary. stop_at: str | None = None if since_ref is not None: since_commit = resolve_commit_ref(root, repo_id, branch, since_ref) if since_commit is None: print(f"❌ Could not resolve --since ref: {since_ref!r}", file=sys.stderr) raise SystemExit(ExitCode.USER_ERROR) stop_at = since_commit.commit_id # 1. Collect all symbols that exist in HEAD snapshot. manifest = get_commit_snapshot_manifest(root, head_commit.commit_id) or {} symbol_map = symbols_for_snapshot( root, manifest, kind_filter=kind_filter, language_filter=language_filter ) # Build the universe of symbol addresses to track, applying doc/import filters. all_current_addrs: set[str] = set() for file_path_str, tree in symbol_map.items(): file_lang = language_of(file_path_str) if not include_docs and file_lang in _DOC_LANGUAGES: continue for addr in tree: if not include_imports and "::import::" in addr: continue all_current_addrs.add(addr) # 2. Walk commits newest-first via BFS (follows both parent_commit_id and # parent2_commit_id so merged feature-branch commits are not missed). commits, truncated = walk_commits_bfs( root, head_commit.commit_id, max_commits=max_commits, stop_at_commit_id=stop_at, ) total_commits = len(commits) # Record the last (newest) commit index at which each symbol was touched. # Index 0 = most recent commit; index N = touched N commits ago. # A symbol at index N means it has been unchanged for N commits since that touch. last_touched: _IntMap = {} for idx, commit in enumerate(commits): if commit.structured_delta is None: continue for op in flat_symbol_ops(commit.structured_delta["ops"]): addr = op["address"] if addr in all_current_addrs and addr not in last_touched: last_touched[addr] = idx # 3. Compute stability for every tracked symbol. # never touched → stable for total_commits (unchanged since first commit / window start). # touched at index N → unchanged for N commits between touch and HEAD. stability: list[tuple[str, int, bool]] = [] for addr in sorted(all_current_addrs): touch_idx = last_touched.get(addr) if touch_idx is None: stability.append((addr, total_commits, True)) else: stability.append((addr, touch_idx, False)) stability.sort(key=lambda t: t[1], reverse=True) ranked = stability[:top] if as_json: filters: _Filters = { "top": top, "kind": kind_filter, "language": language_filter, "since": since_ref, "include_imports": include_imports, "include_docs": include_docs, "max_commits": max_commits, } print(json.dumps( { "from_ref": since_ref or "(beginning)", "to_ref": branch, "commits_analysed": total_commits, "truncated": truncated, "filters": filters, "stable": [ { "address": a, "unchanged_for": s, "since_start_of_range": sf, } for a, s, sf in ranked ], }, indent=2, )) return # Human-readable output. filter_parts: list[str] = [] if kind_filter: filter_parts.append(f"kind={kind_filter}") if language_filter: filter_parts.append(f"language={language_filter}") if since_ref: filter_parts.append(f"since={since_ref}") filters_str = (" " + " ".join(filter_parts)) if filter_parts else "" range_label = f"since {since_ref}" if since_ref else "across all history" print(f"\nSymbol stability — top {len(ranked)} most stable symbols{filters_str}") print(f"Commits analysed: {total_commits} ({range_label})") if truncated: print(f"⚠️ Scan capped at {max_commits} commits — pass --max-commits to extend.") print("") width = len(str(len(ranked))) for rank, (addr, count, since_start) in enumerate(ranked, 1): suffix = " (since start of range)" if since_start else "" label = "commit" if count == 1 else "commits" print(f" {rank:>{width}} {sanitize_display(addr):<60} unchanged for {count:>4} {label}{suffix}") print("") print("These are your bedrock. High stability = safe to build on.")