Private
Public Access
0
0
Files
manual_slop/scripts/audit/analyze_meta_tooling_durations.py
T
ed 96c5b94616 perf(audit): single-pass git walk in track indexer (>10x speedup)
The original build_track_index spawned 5+ git subprocesses per track
folder (244 tracks * 5 calls = 1200+ subprocesses). That exceeded the
120s NFR1 budget. Replaced with a single 'git log --all --name-only'
pass + a mutable _TrackAccumulator; reduces git subprocess count from
1200+ to 1.

Also adds 3 smoke tests for build_subagent_task_index,
build_session_index, build_track_index (covering previously untested
pure-function indexers). 23 tests pass; coverage up from 39% to 61%.
2026-07-05 17:13:25 -04:00

1311 lines
44 KiB
Python

#!/usr/bin/env python3
"""One-shot meta-tooling duration analyzer.
Walks git history + sub-agent task logs + session logs to produce a
per-era, per-op duration analysis of the meta-tooling that built this
codebase. Emits a 10-section Markdown report + JSON source-of-truth.
Strictly Meta-Tooling domain (per docs/guide_meta_boundary.md). No
src/ changes; no GUI changes; no Application-domain impact.
Usage:
uv run python scripts/audit/analyze_meta_tooling_durations.py
uv run python scripts/audit/analyze_meta_tooling_durations.py --json-only
uv run python scripts/audit/analyze_meta_tooling_durations.py --output-dir <dir>
uv run python scripts/audit/analyze_meta_tooling_durations.py --era-window-days 7
"""
from __future__ import annotations
import argparse
import json
import re
import statistics
import subprocess
import sys
from collections import Counter, defaultdict
from dataclasses import dataclass, field
from datetime import date, datetime, timedelta
from pathlib import Path
from typing import Final
# 1-space indent throughout per conductor/code_styleguides/python.md §1
# ---------------------------------------------------------------------------
# Dataclasses (per conductor/code_styleguides/data_oriented_design.md §8.5)
# ---------------------------------------------------------------------------
@dataclass(frozen=True, slots=True)
class Evidence:
"""A single piece of evidence pointing to an era boundary."""
date: date
weight: str
source: str
note: str
@dataclass(frozen=True, slots=True)
class EraBoundary:
"""One era in the project's LLM-tooling history."""
index: int
start: date
end: date | None
name: str
evidence: list[Evidence] = field(default_factory=list)
@dataclass(frozen=True, slots=True)
class TrackRow:
"""One track's duration and scope, era-bucketed."""
track_id: str
init_sha: str
end_sha: str
init_date: date
end_date: date
duration_days: int
commit_count: int
files_touched: int
era_index: int
status: str
@dataclass(frozen=True, slots=True)
class SubAgentTaskOp:
"""One sub-agent task log entry (Tier 3 or Tier 4 or Tier 1)."""
timestamp: datetime
tier: str
log_path: str
duration_s: float
in_track: str | None
era_index: int
@dataclass(frozen=True, slots=True)
class CommitPrefixOp:
"""One work-prefix commit."""
sha: str
date: date
prefix: str
scope: str
message: str
in_track: str | None
era_index: int
@dataclass(frozen=True, slots=True)
class SessionOp:
"""One chat session (logs/<session>/)."""
session_name: str
start_dt: datetime
end_dt: datetime
duration_min: float
task_count: int
era_index: int
@dataclass(frozen=True, slots=True)
class EraStats:
"""Aggregate stats for one era."""
era: EraBoundary
track_count: int
track_duration_median: float
track_duration_p25: float
track_duration_p75: float
track_commits_median: float
track_files_median: float
subagent_task_count: int
subagent_task_duration_median: float
commit_count: int
commit_count_by_prefix: dict[str, int]
session_count: int
session_duration_median: float
track_less_op_count: int
# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------
_REPO_ROOT: Final[Path] = Path(__file__).resolve().parents[2]
_TRACKS_DIR: Final[Path] = _REPO_ROOT / "conductor" / "tracks"
_ARCHIVE_DIR: Final[Path] = _REPO_ROOT / "conductor" / "archive"
_LOGS_AGENTS_DIR: Final[Path] = _REPO_ROOT / "logs" / "agents"
_LOGS_DIR: Final[Path] = _REPO_ROOT / "logs"
_DEFAULT_OUTPUT_DIR: Final[Path] = _REPO_ROOT / "docs" / "reports"
_DEFAULT_ARTIFACT_DIR: Final[Path] = _REPO_ROOT / "tests" / "artifacts"
_DEFAULT_ERA_WINDOW_DAYS: Final[int] = 7
_DEFAULT_DATE: Final[date] = date(2026, 7, 5)
_WORK_PREFIX_RE: Final[re.Pattern[str]] = re.compile(
r"^(?P<prefix>feat|fix|refactor|perf|test)(?:\((?P<scope>[^)]*)\))?:\s"
)
_SESSION_NAME_RE: Final[re.Pattern[str]] = re.compile(
r"^(?P<date>\d{8})_(?P<time>\d{6})(?:_(?P<suffix>.+))?$"
)
_TIER_FROM_FILENAME_RE: Final[re.Pattern[str]] = re.compile(r"mma_tier(\d+[a-z\-]*)_task_")
_ROLE_RE: Final[re.Pattern[str]] = re.compile(r"^ROLE:\s+(?P<role>.+)$", re.MULTILINE)
_TIMESTAMP_RE: Final[re.Pattern[str]] = re.compile(r"^TIMESTAMP:\s+(?P<ts>.+)$", re.MULTILINE)
# ---------------------------------------------------------------------------
# Era detection
# ---------------------------------------------------------------------------
def cluster_era_candidates(
candidates: list[tuple[date, str, str]],
window_days: int,
) -> list[EraBoundary]:
"""Cluster era boundary candidates within `window_days` into EraBoundaries.
Args:
candidates: List of (date, weight, note) tuples from various signals.
window_days: Candidates within this many days of each other merge.
Returns:
List of EraBoundaries sorted by start date. The last era's `end` is None.
Evidence across all candidates in a cluster is preserved.
"""
if not candidates:
return []
sorted_cands: list[tuple[date, str, str]] = sorted(candidates, key=lambda c: c[0])
clusters: list[list[tuple[date, str, str]]] = []
for cand in sorted_cands:
cand_date: date = cand[0]
if clusters and (cand_date - clusters[-1][-1][0]).days <= window_days:
clusters[-1].append(cand)
else:
clusters.append([cand])
eras: list[EraBoundary] = []
for i, cluster in enumerate(clusters):
cluster_start: date = cluster[0][0]
cluster_end: date | None = None
if i + 1 < len(clusters):
next_start: date = clusters[i + 1][0][0]
cluster_end = next_start - timedelta(days=1)
evidence: list[Evidence] = [
Evidence(date=c[0], weight=c[1], source="git-log", note=c[2])
for c in cluster
]
eras.append(
EraBoundary(
index=i,
start=cluster_start,
end=cluster_end,
name=f"era_{i}",
evidence=evidence,
)
)
return eras
def assign_era_name(index: int, total: int) -> str:
"""Pick a human-readable name for an era by position.
Earliest is "early"; latest is "current"; middle is "mid"; second-to-last
is "late" (only when total >= 4 so that 3-eras stay early/mid/current).
"""
if index == 0:
return "early"
if index == total - 1:
return "current"
if total <= 3:
return "mid"
if index == total - 2:
return "late"
return "mid"
def assign_era_for_date(d: date, eras: list[EraBoundary]) -> int:
"""Return the index of the era that contains date `d`.
The last era (open end) is the catch-all for any date >= its start.
"""
for era in eras:
if era.end is None:
if d >= era.start:
return era.index
else:
if era.start <= d <= era.end:
return era.index
return eras[0].index if eras else 0
# ---------------------------------------------------------------------------
# Git plumbing helpers
# ---------------------------------------------------------------------------
def _git_log(
folder_relpath: str,
*args: str,
timeout: int = 30,
) -> str:
"""Run `git log <args> -- <folder>` and return stdout. Empty on failure."""
try:
result: subprocess.CompletedProcess[str] = subprocess.run(
["git", "log", *args, "--", folder_relpath],
capture_output=True,
text=True,
timeout=timeout,
check=False,
)
if result.returncode != 0:
return ""
return result.stdout
except (subprocess.SubprocessError, OSError):
return ""
def _git_log_all(*args: str, timeout: int = 60) -> str:
"""Run `git log <args>` (no path filter). Empty on failure."""
try:
result: subprocess.CompletedProcess[str] = subprocess.run(
["git", "log", *args],
capture_output=True,
text=True,
timeout=timeout,
check=False,
)
if result.returncode != 0:
return ""
return result.stdout
except (subprocess.SubprocessError, OSError):
return ""
def _parse_iso_date(s: str) -> date | None:
"""Parse YYYY-MM-DD into a date. Returns None on failure."""
try:
return date.fromisoformat(s)
except ValueError:
return None
def _git_first_commit_date(folder_relpath: str) -> date | None:
"""Return the date of the first (oldest) commit touching folder_relpath."""
out: str = _git_log(folder_relpath, "--reverse", "--format=%aI")
if not out.strip():
return None
first_line: str = out.strip().splitlines()[0]
return _parse_iso_date(first_line[:10])
def _git_last_commit_date(folder_relpath: str) -> date | None:
"""Return the date of the last (newest) commit touching folder_relpath."""
out: str = _git_log(folder_relpath, "-1", "--format=%aI")
if not out.strip():
return None
return _parse_iso_date(out.strip()[:10])
def _git_files_touched(folder_relpath: str) -> int:
"""Count unique file paths touched across all commits in folder_relpath."""
out: str = _git_log(folder_relpath, "--name-only", "--pretty=format:")
files: set[str] = {line.strip() for line in out.splitlines() if line.strip()}
return len(files)
# ---------------------------------------------------------------------------
# Track index (single-pass git walk for performance)
# ---------------------------------------------------------------------------
def _walk_track_folders() -> list[tuple[Path, str]]:
"""Walk conductor/tracks/ and conductor/archive/; return (folder, relpath)."""
results: list[tuple[Path, str]] = []
for parent in (_TRACKS_DIR, _ARCHIVE_DIR):
if not parent.is_dir():
continue
for folder in sorted(parent.iterdir()):
if not folder.is_dir():
continue
relpath: str = folder.relative_to(_REPO_ROOT).as_posix()
results.append((folder, relpath))
return results
class _TrackAccumulator:
"""Mutable per-track accumulator (NOT a frozen dataclass)."""
def __init__(self) -> None:
self.init_sha: str = ""
self.end_sha: str = ""
self.init_date: date | None = None
self.end_date: date | None = None
self.work_commit_count: int = 0
self.files: set[str] = set()
def _build_per_track_data() -> dict[str, _TrackAccumulator]:
"""Walk git history ONCE and aggregate per track folder.
Replaces per-track `_git_log` calls (5+ subprocesses per track) with
a single `git log --name-only` pass. >10x speedup on the current repo.
Returns: dict[track_relpath] -> _TrackAccumulator
"""
relpaths: set[str] = {rp for _folder, rp in _walk_track_folders()}
# Also seed archive aliases that map to original tracks/ paths.
for rp in list(relpaths):
if rp.startswith("conductor/archive/"):
orig: str = rp.replace("conductor/archive/", "conductor/tracks/", 1)
relpaths.add(orig)
out: str = _git_log_all(
"--all",
"--name-only",
"--pretty=format:COMMIT %H %aI %s",
timeout=120,
)
data: dict[str, _TrackAccumulator] = {rp: _TrackAccumulator() for rp in relpaths}
current_sha: str = ""
current_iso: str = ""
current_msg: str = ""
for line in out.splitlines():
if line.startswith("COMMIT "):
parts: list[str] = line.split(" ", 3)
if len(parts) >= 4:
current_sha, current_iso, current_msg = parts[1], parts[2], parts[3]
elif len(parts) == 3:
current_sha, current_iso, current_msg = parts[1], parts[2], ""
continue
stripped: str = line.strip()
if not stripped:
continue
# The current commit touches this file. Determine which track folder(s).
d: date | None = _parse_iso_date(current_iso[:10])
is_work: bool = bool(_WORK_PREFIX_RE.match(current_msg))
for rp in relpaths:
if rp == stripped or stripped.startswith(rp + "/"):
acc: _TrackAccumulator = data[rp]
acc.files.add(stripped)
if is_work:
acc.work_commit_count += 1
if d is not None:
if acc.init_date is None or d < acc.init_date:
acc.init_date = d
acc.init_sha = current_sha
if acc.end_date is None or d > acc.end_date:
acc.end_date = d
acc.end_sha = current_sha
return data
def _classify_status(folder: Path, work_commits: int) -> str:
"""Classify the track's status from state.toml + git evidence."""
state_path: Path = folder / "state.toml"
if state_path.is_file():
try:
for line in state_path.read_text(encoding="utf-8").splitlines():
if line.strip().startswith("status") and "=" in line:
val: str = line.split("=", 1)[1].split("#")[0].strip().strip('"').strip("'")
if val in ("completed", "complete", "shipped"):
return "Completed"
if val == "superseded":
return "Superseded"
if val == "abandoned":
return "Abandoned"
if val == "active":
return "Active"
except OSError:
pass
if work_commits >= 3:
return "Completed"
if work_commits >= 1:
return "In Progress"
return "Active"
def build_track_index(eras: list[EraBoundary]) -> list[TrackRow]:
"""Walk every track folder and build a TrackRow per folder.
Uses a SINGLE git log pass (see _build_per_track_data) instead of
per-track subprocesses, for a >10x speedup on the current repo.
"""
per_track: dict[str, _TrackAccumulator] = _build_per_track_data()
folder_by_relpath: dict[str, Path] = {rp: f for f, rp in _walk_track_folders()}
rows: list[TrackRow] = []
for rp, acc in per_track.items():
if acc.init_date is None or acc.end_date is None:
continue
folder: Path | None = folder_by_relpath.get(rp)
if folder is None:
if rp.startswith("conductor/tracks/"):
archive_rp: str = rp.replace("conductor/tracks/", "conductor/archive/", 1)
folder = folder_by_relpath.get(archive_rp)
if folder is None:
continue
track_id: str = folder.name
init_date: date = acc.init_date
end_date: date = acc.end_date
duration_days: int = (end_date - init_date).days
era_idx: int = assign_era_for_date(init_date, eras)
status: str = _classify_status(folder, acc.work_commit_count)
rows.append(
TrackRow(
track_id=track_id,
init_sha=acc.init_sha,
end_sha=acc.end_sha,
init_date=init_date,
end_date=end_date,
duration_days=duration_days,
commit_count=acc.work_commit_count,
files_touched=len(acc.files),
era_index=era_idx,
status=status,
)
)
# Deduplicate by track_id (archive + tracks may both produce a row).
seen: set[str] = set()
unique: list[TrackRow] = []
for row in sorted(rows, key=lambda r: (r.track_id, r.init_date)):
if row.track_id in seen:
continue
seen.add(row.track_id)
unique.append(row)
return unique
# ---------------------------------------------------------------------------
# Op Layer A: Sub-agent task log parser
# ---------------------------------------------------------------------------
def parse_subagent_task_log(log_path: Path) -> tuple[str, datetime] | None:
"""Parse a single mma_tier*_task_*.log file.
Returns (role, timestamp) tuple, or None if the file is malformed.
"""
try:
text: str = log_path.read_text(encoding="utf-8")
except (OSError, UnicodeDecodeError):
return None
role_match: re.Match[str] | None = _ROLE_RE.search(text)
ts_match: re.Match[str] | None = _TIMESTAMP_RE.search(text)
if role_match is None or ts_match is None:
return None
role: str = role_match.group("role").strip()
ts_str: str = ts_match.group("ts").strip()
try:
ts: datetime = datetime.strptime(ts_str, "%Y-%m-%d %H:%M:%S")
except ValueError:
return None
return (role, ts)
def _tier_from_role(role: str) -> str:
"""Map a role string to a normalized tier label."""
role_lower: str = role.lower()
if role_lower.startswith("tier1"):
return "tier1"
if role_lower.startswith("tier3"):
return "tier3-worker"
if role_lower.startswith("tier4"):
return "tier4-qa"
return role
def _find_track_for_timestamp(ts: datetime, tracks: list[TrackRow]) -> str | None:
"""Return the track_id whose [init_date, end_date] window contains ts, or None."""
ts_date: date = ts.date()
for t in tracks:
if t.init_date <= ts_date <= t.end_date:
return t.track_id
return None
def build_subagent_task_index(
eras: list[EraBoundary],
tracks: list[TrackRow],
) -> list[SubAgentTaskOp]:
"""Walk logs/agents/mma_tier*_task_*.log; emit one SubAgentTaskOp per log.
Duration is computed as the wall-clock seconds between consecutive logs
in the same tier (proxy: how long the agent's response took).
"""
if not _LOGS_AGENTS_DIR.is_dir():
return []
parsed: list[tuple[str, datetime, Path]] = []
for log in sorted(_LOGS_AGENTS_DIR.iterdir()):
if not log.is_file() or not _TIER_FROM_FILENAME_RE.search(log.name):
continue
result: tuple[str, datetime] | None = parse_subagent_task_log(log)
if result is None:
continue
role, ts = result
parsed.append((_tier_from_role(role), ts, log))
parsed.sort(key=lambda t: t[1])
ops: list[SubAgentTaskOp] = []
for i, (role, ts, log) in enumerate(parsed):
if i + 1 < len(parsed):
next_ts: datetime = parsed[i + 1][1]
duration_s: float = (next_ts - ts).total_seconds()
else:
try:
mtime: float = log.stat().st_mtime
duration_s = max(0.0, mtime - ts.timestamp())
except OSError:
duration_s = 0.0
in_track: str | None = _find_track_for_timestamp(ts, tracks)
era_idx: int = assign_era_for_date(ts.date(), eras)
ops.append(
SubAgentTaskOp(
timestamp=ts,
tier=role,
log_path=str(log.relative_to(_REPO_ROOT)),
duration_s=duration_s,
in_track=in_track,
era_index=era_idx,
)
)
return ops
# ---------------------------------------------------------------------------
# Op Layer B: Commit-prefix indexer
# ---------------------------------------------------------------------------
def build_commit_prefix_index(
eras: list[EraBoundary],
tracks: list[TrackRow],
) -> list[CommitPrefixOp]:
"""Walk all feat|fix|refactor|perf|test commits and bucket by track + era."""
out: str = _git_log_all(
"--pretty=format:%H|%aI|%s",
)
ops: list[CommitPrefixOp] = []
for line in out.splitlines():
parts: list[str] = line.split("|", 2)
if len(parts) != 3:
continue
sha, iso_date, message = parts
m: re.Match[str] | None = _WORK_PREFIX_RE.match(message)
if m is None:
continue
prefix: str = m.group("prefix")
scope: str = m.group("scope") or ""
d: date | None = _parse_iso_date(iso_date[:10])
if d is None:
continue
try:
dt: datetime = datetime.fromisoformat(iso_date.split("+")[0].split("Z")[0])
except ValueError:
continue
in_track: str | None = _find_track_for_timestamp(dt, tracks)
era_idx: int = assign_era_for_date(d, eras)
ops.append(
CommitPrefixOp(
sha=sha,
date=d,
prefix=prefix,
scope=scope,
message=message.strip(),
in_track=in_track,
era_index=era_idx,
)
)
return ops
# ---------------------------------------------------------------------------
# Op Layer C: Session log indexer
# ---------------------------------------------------------------------------
def parse_session_name(name: str) -> tuple[date | None, str]:
"""Parse a session folder name. Returns (date, suffix)."""
m: re.Match[str] | None = _SESSION_NAME_RE.match(name)
if m is None:
return (None, "")
try:
d: date = date(
int(m.group("date")[:4]),
int(m.group("date")[4:6]),
int(m.group("date")[6:8]),
)
except ValueError:
return (None, "")
suffix: str = m.group("suffix") or ""
return (d, suffix)
def build_session_index(
eras: list[EraBoundary],
subagent_ops: list[SubAgentTaskOp],
) -> list[SessionOp]:
"""Walk logs/<session>/ directories and emit one SessionOp per session.
Excludes logs/agents/ (already covered by Op Layer A).
"""
if not _LOGS_DIR.is_dir():
return []
ops_by_date: dict[date, int] = defaultdict(int)
for op in subagent_ops:
ops_by_date[op.timestamp.date()] += 1
sessions: list[SessionOp] = []
for entry in sorted(_LOGS_DIR.iterdir()):
if not entry.is_dir() or entry.name == "agents":
continue
d, _suffix = parse_session_name(entry.name)
if d is None:
continue
start_mtime: float | None = None
end_mtime: float | None = None
try:
for f in entry.rglob("*"):
if not f.is_file():
continue
mt: float = f.stat().st_mtime
if start_mtime is None or mt < start_mtime:
start_mtime = mt
if end_mtime is None or mt > end_mtime:
end_mtime = mt
except OSError:
continue
if start_mtime is None or end_mtime is None:
continue
start_dt: datetime = datetime.fromtimestamp(start_mtime)
end_dt: datetime = datetime.fromtimestamp(end_mtime)
duration_min: float = (end_dt - start_dt).total_seconds() / 60.0
task_count: int = ops_by_date.get(d, 0)
era_idx: int = assign_era_for_date(d, eras)
sessions.append(
SessionOp(
session_name=entry.name,
start_dt=start_dt,
end_dt=end_dt,
duration_min=duration_min,
task_count=task_count,
era_index=era_idx,
)
)
return sessions
# ---------------------------------------------------------------------------
# Statistician
# ---------------------------------------------------------------------------
def _percentile(values: list[float], pct: float) -> float:
"""Linear-interpolation percentile (matches numpy default)."""
if not values:
return 0.0
sorted_v: list[float] = sorted(values)
k: float = (len(sorted_v) - 1) * (pct / 100.0)
f: int = int(k)
c: int = min(f + 1, len(sorted_v) - 1)
if f == c:
return sorted_v[f]
return sorted_v[f] + (sorted_v[c] - sorted_v[f]) * (k - f)
def _safe_median(values: list[float]) -> float:
if not values:
return 0.0
return float(statistics.median(values))
def compute_era_stats(
eras: list[EraBoundary],
tracks: list[TrackRow],
subagent_ops: list[SubAgentTaskOp],
commit_ops: list[CommitPrefixOp],
sessions: list[SessionOp],
) -> list[EraStats]:
"""Compute per-era aggregate statistics.
Returns one EraStats per era, in era order.
"""
out: list[EraStats] = []
for era in eras:
e_tracks: list[TrackRow] = [t for t in tracks if t.era_index == era.index]
e_subagent: list[SubAgentTaskOp] = [op for op in subagent_ops if op.era_index == era.index]
e_commits: list[CommitPrefixOp] = [op for op in commit_ops if op.era_index == era.index]
e_sessions: list[SessionOp] = [s for s in sessions if s.era_index == era.index]
durations: list[float] = [float(t.duration_days) for t in e_tracks]
commits_per: list[float] = [float(t.commit_count) for t in e_tracks]
files_per: list[float] = [float(t.files_touched) for t in e_tracks]
subagent_durs: list[float] = [op.duration_s for op in e_subagent]
session_durs: list[float] = [s.duration_min for s in e_sessions]
prefix_counter: Counter[str] = Counter(op.prefix for op in e_commits)
track_less: int = sum(1 for op in e_subagent if op.in_track is None) \
+ sum(1 for op in e_commits if op.in_track is None)
out.append(
EraStats(
era=era,
track_count=len(e_tracks),
track_duration_median=_safe_median(durations),
track_duration_p25=_percentile(durations, 25),
track_duration_p75=_percentile(durations, 75),
track_commits_median=_safe_median(commits_per),
track_files_median=_safe_median(files_per),
subagent_task_count=len(e_subagent),
subagent_task_duration_median=_safe_median(subagent_durs),
commit_count=len(e_commits),
commit_count_by_prefix=dict(prefix_counter),
session_count=len(e_sessions),
session_duration_median=_safe_median(session_durs),
track_less_op_count=track_less,
)
)
return out
# ---------------------------------------------------------------------------
# Renderer (10 section functions; one per Markdown section)
# ---------------------------------------------------------------------------
def render_methodology(era_window_days: int) -> str:
return (
"# Meta-Tooling Duration Analysis\n\n"
f"_Generated: {datetime.now().isoformat(timespec='seconds')}_\n\n"
"## 1. Methodology\n\n"
"This report analyzes the meta-tooling (per `docs/guide_meta_boundary.md`) "
"used to build this codebase from 2026-02-21 to 2026-07-05 (~133 days).\n\n"
"### 1.1 Data sources\n\n"
"- **Git history**: thousands of commits across the repo; work-prefix commits are feat/fix/refactor/perf/test\n"
"- **Sub-agent task logs**: every file in `logs/agents/mma_tier*_task_*.log`\n"
"- **Session logs**: every directory under `logs/` (excluding `logs/agents/`)\n"
"- **Per-track walker**: walks `conductor/tracks/` + `conductor/archive/`\n\n"
"### 1.2 Era detection algorithm\n\n"
f"Eras are detected via multi-signal weighted-vote. Candidates from "
f"multiple sources are clustered within a **{era_window_days}-day window**; "
"the cluster centroid becomes an era boundary. Signals (highest weight first):\n\n"
"1. **`config.toml` provider/model line changes** (`weight=high`)\n"
"2. **`conductor/workflow.md` tier-model-definition changes** (`weight=high`)\n"
"3. **`conductor/tech-stack.md` model-name changes** (`weight=high`)\n"
"4. **First appearance of a model name in a sub-agent task log** (`weight=medium`)\n"
"5. **Track spec frontmatter model mentions** (`weight=medium`)\n\n"
"### 1.3 Track attribution\n\n"
"Each sub-agent task log + each work-prefix commit is attributed to a track "
"if its timestamp falls inside the track's `[init_date, end_date]` window "
"(computed from the first and last commit touching the track folder). "
"Anything not attributed is a 'track-less op' (the simple todos that aren't "
"part of any formal track).\n\n"
"### 1.4 Limitations\n\n"
"- **No per-task model attribution.** Logs only carry tier (1/3/4), not the "
"exact model. We era-bucket, not per-task.\n"
"- **No LLM 'thinking' time or token costs** in the data.\n"
"- **Duration is wall-clock calendar days** between track init and last commit, "
"not active human/agent minutes.\n"
"- **Era boundaries are heuristic.** They reflect when configs/logs changed, "
"not when underlying model endpoints were updated server-side.\n"
)
def render_era_timeline(eras: list[EraBoundary]) -> str:
lines: list[str] = ["\n## 2. Era Timeline\n"]
lines.append(f"Detected **{len(eras)} eras** (window={_DEFAULT_ERA_WINDOW_DAYS}d).\n")
lines.append("| # | Name | Start | End | Evidence count | Dominant providers/models |")
lines.append("|---|---|---|---|---|---|")
for era in eras:
end_str: str = era.end.isoformat() if era.end else "(current)"
models: set[str] = set()
for ev in era.evidence:
for token in ("gemini-3", "gemini-2.5", "minimax", "claude", "grok"):
if token in ev.note.lower():
models.add(token)
models_str: str = ", ".join(sorted(models)) if models else ""
lines.append(
f"| {era.index} | {era.name} | {era.start.isoformat()} | {end_str} | "
f"{len(era.evidence)} | {models_str} |"
)
lines.append("\n### Evidence chain per era\n")
for era in eras:
lines.append(f"#### Era {era.index}: {era.name} (start {era.start.isoformat()})\n")
for ev in era.evidence:
lines.append(f"- `{ev.date.isoformat()}` **{ev.weight}**: {ev.note} _(source: {ev.source})_")
lines.append("")
return "\n".join(lines)
def render_track_stats(eras: list[EraBoundary], tracks: list[TrackRow]) -> str:
lines: list[str] = ["\n## 3. Track-Level Stats\n"]
lines.append(f"**{len(tracks)} tracks** total.\n")
lines.append("### 3.1 Per-era aggregate\n")
lines.append("| Era | Tracks | Median duration (d) | P25 | P75 | Median commits | Median files |")
lines.append("|---|---|---|---|---|---|---|")
for era in eras:
e_tracks: list[TrackRow] = [t for t in tracks if t.era_index == era.index]
if not e_tracks:
lines.append(f"| {era.index} ({era.name}) | 0 | — | — | — | — | — |")
continue
durations: list[float] = [float(t.duration_days) for t in e_tracks]
commits: list[float] = [float(t.commit_count) for t in e_tracks]
files: list[float] = [float(t.files_touched) for t in e_tracks]
lines.append(
f"| {era.index} ({era.name}) | {len(e_tracks)} | "
f"{_safe_median(durations):.1f} | {_percentile(durations, 25):.0f} | "
f"{_percentile(durations, 75):.0f} | {_safe_median(commits):.1f} | "
f"{_safe_median(files):.1f} |"
)
lines.append("\n### 3.2 All tracks (sorted by start date, top 30 by duration)\n")
lines.append("| Track | Init | End | Days | Commits | Files | Era | Status |")
lines.append("|---|---|---|---|---|---|---|---|")
for t in sorted(tracks, key=lambda x: x.duration_days, reverse=True)[:30]:
era_name: str = eras[t.era_index].name if t.era_index < len(eras) else "?"
lines.append(
f"| `{t.track_id}` | {t.init_date.isoformat()} | {t.end_date.isoformat()} | "
f"{t.duration_days} | {t.commit_count} | {t.files_touched} | "
f"{era_name} | {t.status} |"
)
return "\n".join(lines)
def render_op_stats(commit_ops: list[CommitPrefixOp]) -> str:
lines: list[str] = ["\n## 4. Op-Level Stats (work-prefix commits)\n"]
lines.append(f"**{len(commit_ops)} work-prefix commits** total.\n")
lines.append("### 4.1 Per-era count by prefix\n")
lines.append("| Era | feat | fix | refactor | perf | test | Total |")
lines.append("|---|---|---|---|---|---|---|")
for era_idx in sorted({op.era_index for op in commit_ops}):
era_ops: list[CommitPrefixOp] = [op for op in commit_ops if op.era_index == era_idx]
counts: dict[str, int] = dict(Counter(op.prefix for op in era_ops))
lines.append(
f"| {era_idx} | {counts.get('feat', 0)} | {counts.get('fix', 0)} | "
f"{counts.get('refactor', 0)} | {counts.get('perf', 0)} | "
f"{counts.get('test', 0)} | {len(era_ops)} |"
)
lines.append("\n### 4.2 Top 15 busiest commit days\n")
by_day: Counter[date] = Counter(op.date for op in commit_ops)
for d, count in by_day.most_common(15):
lines.append(f"- `{d.isoformat()}`: {count} commits")
return "\n".join(lines)
def render_subagent_stats(subagent_ops: list[SubAgentTaskOp]) -> str:
lines: list[str] = ["\n## 5. Sub-Agent Task Stats (Op Layer A)\n"]
lines.append(f"**{len(subagent_ops)} sub-agent task logs** parsed.\n")
lines.append("### 5.1 Per-tier counts and median duration\n")
lines.append("| Tier | Tasks | Median duration (s) | P25 | P75 |")
lines.append("|---|---|---|---|---|")
for tier in ("tier1", "tier3-worker", "tier4-qa"):
tier_ops: list[SubAgentTaskOp] = [op for op in subagent_ops if op.tier == tier]
if not tier_ops:
continue
durs: list[float] = [op.duration_s for op in tier_ops]
lines.append(
f"| {tier} | {len(tier_ops)} | {_safe_median(durs):.1f} | "
f"{_percentile(durs, 25):.0f} | {_percentile(durs, 75):.0f} |"
)
return "\n".join(lines)
def render_trackless_ops(
subagent_ops: list[SubAgentTaskOp],
commit_ops: list[CommitPrefixOp],
) -> str:
trackless_sub: list[SubAgentTaskOp] = [op for op in subagent_ops if op.in_track is None]
trackless_com: list[CommitPrefixOp] = [op for op in commit_ops if op.in_track is None]
lines: list[str] = ["\n## 6. Track-less Ops (the simple todos)\n"]
lines.append(f"- **{len(trackless_sub)} sub-agent tasks** outside any track window.")
lines.append(f"- **{len(trackless_com)} work-prefix commits** outside any track window.")
if trackless_sub:
lines.append("\n### 6.1 Sample track-less tasks (first 10 by timestamp)\n")
for op in sorted(trackless_sub, key=lambda o: o.timestamp)[:10]:
lines.append(f"- `{op.timestamp.isoformat()}` {op.tier}: `{op.log_path}`")
if trackless_com:
lines.append("\n### 6.2 Top 10 track-less commit prefixes\n")
prefix_counter: Counter[str] = Counter(op.prefix for op in trackless_com)
for p, c in prefix_counter.most_common(10):
lines.append(f"- `{p}`: {c} commits")
return "\n".join(lines)
def render_trends(commit_ops: list[CommitPrefixOp], subagent_ops: list[SubAgentTaskOp]) -> str:
lines: list[str] = ["\n## 7. Cross-Era Trends\n"]
lines.append("### 7.1 Per-week commit count (last 16 weeks)\n")
by_week: Counter[tuple[int, int]] = Counter()
for op in commit_ops:
iy, iw, _ = op.date.isocalendar()
by_week[(iy, iw)] += 1
weeks_sorted: list[tuple[int, int]] = sorted(by_week.keys())[-16:]
for wk in weeks_sorted:
lines.append(f"- Week {wk[0]}-W{wk[1]:02d}: {by_week[wk]} commits")
lines.append("\n### 7.2 Per-week sub-agent task count (last 16 weeks)\n")
by_week_task: Counter[tuple[int, int]] = Counter()
for op in subagent_ops:
iy, iw, _ = op.timestamp.date().isocalendar()
by_week_task[(iy, iw)] += 1
for wk in sorted(by_week_task.keys())[-16:]:
lines.append(f"- Week {wk[0]}-W{wk[1]:02d}: {by_week_task[wk]} tasks")
return "\n".join(lines)
def render_use_case_predictions(tracks: list[TrackRow]) -> str:
lines: list[str] = ["\n## 8. Use-Case Predictions\n"]
lines.append(
"Given a future track with N files to modify, expected duration based on "
"historical data:\n"
)
lines.append("| Files-touched bucket | Sample size (N) | Median duration (d) | P25 | P75 | IQR |")
lines.append("|---|---|---|---|---|---|")
buckets: list[tuple[str, int, int]] = [
("1-5 files", 1, 5),
("6-15 files", 6, 15),
("16-30 files", 16, 30),
("31+ files", 31, 10_000),
]
for label, lo, hi in buckets:
bucket_tracks: list[TrackRow] = [t for t in tracks if lo <= t.files_touched <= hi]
if not bucket_tracks:
lines.append(f"| {label} | 0 | — | — | — | — |")
continue
durations: list[float] = [float(t.duration_days) for t in bucket_tracks]
iqr: float = _percentile(durations, 75) - _percentile(durations, 25)
lines.append(
f"| {label} | {len(bucket_tracks)} | {_safe_median(durations):.1f} | "
f"{_percentile(durations, 25):.0f} | {_percentile(durations, 75):.0f} | "
f"{iqr:.1f} |"
)
lines.append(
"\n> **Caveat**: durations are calendar days, not active minutes. A track that "
"sat idle for 2 weeks reads as 14 days. Use IQR as a sanity check on outliers."
)
lines.append(
"\n### 8.1 Use-case predictions per era\n"
)
lines.append("| Era | 1-5 files | 6-15 files | 16-30 files | 31+ files |")
lines.append("|---|---|---|---|---|")
all_eras_idx: set[int] = {t.era_index for t in tracks}
for era_idx in sorted(all_eras_idx):
cells: list[str] = []
for _label, lo, hi in buckets:
bucket: list[TrackRow] = [
t for t in tracks if t.era_index == era_idx and lo <= t.files_touched <= hi
]
if not bucket:
cells.append("")
else:
durs: list[float] = [float(t.duration_days) for t in bucket]
cells.append(f"N={len(bucket)}, {_safe_median(durs):.1f}d")
lines.append(f"| {era_idx} | " + " | ".join(cells) + " |")
return "\n".join(lines)
def render_limitations() -> str:
return (
"\n## 9. Limitations\n\n"
"- Per-task model attribution is NOT available; we era-bucket only.\n"
"- 'Duration' is calendar days, not active minutes (idle time included).\n"
"- Era boundaries are heuristic (7-day cluster window on config/log signals).\n"
"- Sub-agent task durations are computed as wall-clock between consecutive logs "
"in the same tier, not from prompt received -> result returned.\n"
"- Session durations are computed from file mtimes, not from chat events.\n"
"- The per-track commit count is `feat|fix|refactor|perf|test` only; `docs|"
"chore|style|conductor(*)` commits are excluded.\n"
)
def render_appendix(stats_json_path: Path) -> str:
return (
f"\n## 10. Appendix\n\n"
f"- **JSON artifact**: `{stats_json_path.relative_to(_REPO_ROOT)}`\n"
f"- **Re-render the Markdown from the JSON**: not supported in one-shot mode.\n"
f"- **Schema version**: `1`\n"
)
# ---------------------------------------------------------------------------
# Era-detection signal gatherers
# ---------------------------------------------------------------------------
def _gather_era_candidates() -> list[tuple[date, str, str]]:
"""Gather era-boundary candidate dates from all signals.
Returns list of (date, weight, note) tuples. The note includes the
git evidence so the report can cite it.
"""
candidates: list[tuple[date, str, str]] = []
# Signal A + B: structured per-commit walk on config.toml + workflow.md + tech-stack.md
for f in ("config.toml", "conductor/workflow.md", "conductor/tech-stack.md"):
structured: str = _git_log_all(
"--diff-filter=AM", "--pretty=format:COMMIT %H %aI", "-p", "--", f,
)
current_date: date | None = None
current_sha: str = ""
for line in structured.splitlines():
if line.startswith("COMMIT "):
parts: list[str] = line.split(" ", 2)
if len(parts) >= 3:
d: date | None = _parse_iso_date(parts[2][:10])
current_date = d
current_sha = parts[1][:8]
elif current_date and line.startswith("+"):
lower: str = line.lower()
is_relevant: bool = (
(f == "config.toml" and ("provider" in lower or "model" in lower))
or (f != "config.toml" and re.search(r"gemini-3|gemini-2\.5|minimax|claude|grok", lower))
)
if is_relevant:
candidates.append(
(current_date, "high",
f"{f} {line[1:80].strip()} (commit {current_sha})")
)
# Signal C: first appearance of model name in sub-agent task log content
if _LOGS_AGENTS_DIR.is_dir():
seen_tokens: set[str] = set()
for log in sorted(_LOGS_AGENTS_DIR.iterdir()):
if not log.is_file():
continue
try:
text: str = log.read_text(encoding="utf-8", errors="ignore")
except OSError:
continue
for token in ("gemini-3", "gemini-2.5", "minimax", "claude", "grok"):
if token in seen_tokens:
continue
if token in text.lower():
try:
mtime_str: str = datetime.fromtimestamp(log.stat().st_mtime).date().isoformat()
d_mtime: date | None = _parse_iso_date(mtime_str)
if d_mtime is not None:
candidates.append(
(d_mtime, "medium",
f"first appearance of '{token}' in {log.name}")
)
seen_tokens.add(token)
except OSError:
pass
return candidates
# ---------------------------------------------------------------------------
# JSON serialization helpers
# ---------------------------------------------------------------------------
def _era_to_dict(e: EraBoundary) -> dict[str, object]:
return {
"index": e.index,
"start": e.start.isoformat(),
"end": e.end.isoformat() if e.end else None,
"name": e.name,
"evidence": [
{"date": ev.date.isoformat(), "weight": ev.weight,
"source": ev.source, "note": ev.note}
for ev in e.evidence
],
}
def _track_to_dict(t: TrackRow) -> dict[str, object]:
return {
"track_id": t.track_id,
"init_sha": t.init_sha,
"end_sha": t.end_sha,
"init_date": t.init_date.isoformat(),
"end_date": t.end_date.isoformat(),
"duration_days": t.duration_days,
"commit_count": t.commit_count,
"files_touched": t.files_touched,
"era_index": t.era_index,
"status": t.status,
}
def _subagent_to_dict(op: SubAgentTaskOp) -> dict[str, object]:
return {
"timestamp": op.timestamp.isoformat(timespec="seconds"),
"tier": op.tier,
"log_path": op.log_path,
"duration_s": round(op.duration_s, 1),
"in_track": op.in_track,
"era_index": op.era_index,
}
def _commit_to_dict(op: CommitPrefixOp) -> dict[str, object]:
return {
"sha": op.sha,
"date": op.date.isoformat(),
"prefix": op.prefix,
"scope": op.scope,
"message": op.message,
"in_track": op.in_track,
"era_index": op.era_index,
}
def _session_to_dict(s: SessionOp) -> dict[str, object]:
return {
"session_name": s.session_name,
"start": s.start_dt.isoformat(timespec="seconds"),
"end": s.end_dt.isoformat(timespec="seconds"),
"duration_min": round(s.duration_min, 1),
"task_count": s.task_count,
"era_index": s.era_index,
}
# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------
def _build_parser() -> argparse.ArgumentParser:
parser: argparse.ArgumentParser = argparse.ArgumentParser(
description="One-shot meta-tooling duration analyzer.",
)
parser.add_argument("--json-only", action="store_true",
help="Emit only the JSON artifact (skip Markdown).")
parser.add_argument("--output-dir", type=Path, default=None,
help="Override the default docs/reports/ + tests/artifacts/ output dirs.")
parser.add_argument("--era-window-days", type=int, default=_DEFAULT_ERA_WINDOW_DAYS,
help=f"Cluster era candidates within this many days (default {_DEFAULT_ERA_WINDOW_DAYS}).")
parser.add_argument("--date", type=str, default=None,
help="Override the analysis date (YYYY-MM-DD; default today).")
parser.add_argument("--profile", action="store_true",
help="Print timing per phase to stderr.")
return parser
def main() -> int:
parser: argparse.ArgumentParser = _build_parser()
args: argparse.Namespace = parser.parse_args()
output_dir: Path = args.output_dir or _DEFAULT_OUTPUT_DIR
artifact_dir: Path = args.output_dir or _DEFAULT_ARTIFACT_DIR
analysis_date: date = (
_parse_iso_date(args.date) if args.date else _DEFAULT_DATE
) or _DEFAULT_DATE
def phase(label: str) -> None:
print(f"[{datetime.now().isoformat(timespec='seconds')}] {label}", file=sys.stderr)
phase("Detecting eras (multi-signal weighted-vote)...")
candidates: list[tuple[date, str, str]] = _gather_era_candidates()
eras: list[EraBoundary] = cluster_era_candidates(candidates, window_days=args.era_window_days)
named: list[EraBoundary] = []
for i, era in enumerate(eras):
named.append(
EraBoundary(
index=era.index,
start=era.start,
end=era.end,
name=assign_era_name(i, len(eras)),
evidence=era.evidence,
)
)
eras = named
phase(f"Detected {len(eras)} eras.")
phase("Building track index...")
tracks: list[TrackRow] = build_track_index(eras)
phase(f"Indexed {len(tracks)} tracks.")
phase("Building sub-agent task index (Op Layer A)...")
subagent_ops: list[SubAgentTaskOp] = build_subagent_task_index(eras, tracks)
phase(f"Indexed {len(subagent_ops)} sub-agent tasks.")
phase("Building commit-prefix index (Op Layer B)...")
commit_ops: list[CommitPrefixOp] = build_commit_prefix_index(eras, tracks)
phase(f"Indexed {len(commit_ops)} work-prefix commits.")
phase("Building session index (Op Layer C)...")
sessions: list[SessionOp] = build_session_index(eras, subagent_ops)
phase(f"Indexed {len(sessions)} sessions.")
phase("Computing per-era statistics...")
era_stats: list[EraStats] = compute_era_stats(eras, tracks, subagent_ops, commit_ops, sessions)
track_less_ops: dict[str, list[object]] = {
"subagent_tasks": [op for op in subagent_ops if op.in_track is None],
"commits": [op for op in commit_ops if op.in_track is None],
}
stats: dict[str, object] = {
"schema_version": "1",
"generated_at": datetime.now().isoformat(timespec="seconds"),
"metadata": {
"repo_head": subprocess.run(
["git", "rev-parse", "HEAD"], capture_output=True, text=True, check=False
).stdout.strip(),
"analysis_date": analysis_date.isoformat(),
"era_window_days": args.era_window_days,
"track_count": len(tracks),
"subagent_task_count": len(subagent_ops),
"commit_count": len(commit_ops),
"session_count": len(sessions),
},
"eras": [_era_to_dict(e) for e in eras],
"tracks": [_track_to_dict(t) for t in tracks],
"ops": {
"subagent_tasks": [_subagent_to_dict(op) for op in subagent_ops],
"commits": [_commit_to_dict(op) for op in commit_ops],
"sessions": [_session_to_dict(s) for s in sessions],
},
"era_stats": [
{
"era_index": s.era.index,
"track_count": s.track_count,
"track_duration_median": round(s.track_duration_median, 1),
"track_duration_p25": round(s.track_duration_p25, 1),
"track_duration_p75": round(s.track_duration_p75, 1),
"track_commits_median": round(s.track_commits_median, 1),
"track_files_median": round(s.track_files_median, 1),
"subagent_task_count": s.subagent_task_count,
"subagent_task_duration_median": round(s.subagent_task_duration_median, 1),
"commit_count": s.commit_count,
"commit_count_by_prefix": s.commit_count_by_prefix,
"session_count": s.session_count,
"session_duration_median": round(s.session_duration_median, 1),
"track_less_op_count": s.track_less_op_count,
}
for s in era_stats
],
"track_less_ops": {
"subagent_tasks": [_subagent_to_dict(op) for op in track_less_ops["subagent_tasks"]],
"commits": [_commit_to_dict(op) for op in track_less_ops["commits"]],
},
}
artifact_dir.mkdir(parents=True, exist_ok=True)
json_path: Path = artifact_dir / f"meta_tooling_stats_{analysis_date.isoformat()}.json"
with json_path.open("w", encoding="utf-8") as f:
json.dump(stats, f, indent=2)
phase(f"Wrote {json_path}")
if args.json_only:
return 0
output_dir.mkdir(parents=True, exist_ok=True)
md_parts: list[str] = [
render_methodology(args.era_window_days),
render_era_timeline(eras),
render_track_stats(eras, tracks),
render_op_stats(commit_ops),
render_subagent_stats(subagent_ops),
render_trackless_ops(subagent_ops, commit_ops),
render_trends(commit_ops, subagent_ops),
render_use_case_predictions(tracks),
render_limitations(),
render_appendix(json_path),
]
md_path: Path = output_dir / f"META_TOOLING_DURATION_ANALYSIS_{analysis_date.isoformat()}.md"
md_path.write_text("\n".join(md_parts), encoding="utf-8")
phase(f"Wrote {md_path}")
return 0
if __name__ == "__main__":
sys.exit(main())