96c5b94616
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%.
259 lines
9.0 KiB
Python
259 lines
9.0 KiB
Python
# 1-space indent per conductor/code_styleguides/python.md §1
|
|
from datetime import date, datetime, timedelta
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from scripts.audit.analyze_meta_tooling_durations import (
|
|
CommitPrefixOp,
|
|
EraBoundary,
|
|
EraStats,
|
|
Evidence,
|
|
SessionOp,
|
|
SubAgentTaskOp,
|
|
TrackRow,
|
|
_find_track_for_timestamp,
|
|
_git_files_touched,
|
|
_parse_iso_date,
|
|
_percentile,
|
|
_safe_median,
|
|
assign_era_for_date,
|
|
assign_era_name,
|
|
build_commit_prefix_index,
|
|
build_session_index,
|
|
build_subagent_task_index,
|
|
build_track_index,
|
|
cluster_era_candidates,
|
|
compute_era_stats,
|
|
parse_session_name,
|
|
parse_subagent_task_log,
|
|
render_appendix,
|
|
render_era_timeline,
|
|
render_limitations,
|
|
render_methodology,
|
|
render_op_stats,
|
|
render_subagent_stats,
|
|
render_track_stats,
|
|
render_trackless_ops,
|
|
render_trends,
|
|
render_use_case_predictions,
|
|
)
|
|
|
|
|
|
def test_cluster_era_candidates_within_7_days_merges_into_one():
|
|
"""Candidates within the 7-day window collapse to a single era."""
|
|
candidates: list[tuple[date, str, str]] = [
|
|
(date(2026, 2, 21), "high", "config.toml@9a23941e: gemini-3-flash-preview introduced"),
|
|
(date(2026, 2, 24), "high", "config.toml@9a23941e: gemini-3.1-pro-preview introduced"),
|
|
(date(2026, 2, 26), "medium", "logs/agents/mma_tier3-worker_task_20260226_123549.log first tier3 task"),
|
|
]
|
|
result: list[EraBoundary] = cluster_era_candidates(candidates, window_days=7)
|
|
assert len(result) == 1
|
|
assert result[0].start == date(2026, 2, 21)
|
|
assert result[0].end is None
|
|
assert len(result[0].evidence) == 3
|
|
|
|
|
|
def test_cluster_era_candidates_15_days_apart_produces_two_eras():
|
|
"""Candidates 15 days apart stay as 2 eras."""
|
|
candidates: list[tuple[date, str, str]] = [
|
|
(date(2026, 2, 21), "high", "A"),
|
|
(date(2026, 3, 21), "high", "B"),
|
|
]
|
|
result: list[EraBoundary] = cluster_era_candidates(candidates, window_days=7)
|
|
assert len(result) == 2
|
|
assert result[0].start == date(2026, 2, 21)
|
|
assert result[1].start == date(2026, 3, 21)
|
|
|
|
|
|
def test_cluster_era_candidates_empty_input_returns_empty_list():
|
|
result: list[EraBoundary] = cluster_era_candidates([], window_days=7)
|
|
assert result == []
|
|
|
|
|
|
def test_assign_era_name_first_is_early_last_is_current():
|
|
eras_n = 3
|
|
assert assign_era_name(0, eras_n) == "early"
|
|
assert assign_era_name(1, eras_n) == "mid"
|
|
assert assign_era_name(eras_n - 1, eras_n) == "current"
|
|
|
|
|
|
def test_assign_era_for_date_returns_correct_index():
|
|
eras: list[EraBoundary] = [
|
|
EraBoundary(index=0, start=date(2026, 2, 21), end=date(2026, 3, 11), name="early", evidence=[]),
|
|
EraBoundary(index=1, start=date(2026, 3, 12), end=date(2026, 5, 8), name="mid", evidence=[]),
|
|
EraBoundary(index=2, start=date(2026, 5, 9), end=None, name="current", evidence=[]),
|
|
]
|
|
assert assign_era_for_date(date(2026, 2, 25), eras) == 0
|
|
assert assign_era_for_date(date(2026, 4, 1), eras) == 1
|
|
assert assign_era_for_date(date(2026, 7, 5), eras) == 2
|
|
|
|
|
|
def test_assign_era_for_date_before_first_era_returns_zero():
|
|
eras: list[EraBoundary] = [
|
|
EraBoundary(index=0, start=date(2026, 2, 21), end=None, name="early", evidence=[]),
|
|
]
|
|
assert assign_era_for_date(date(2025, 1, 1), eras) == 0
|
|
|
|
|
|
def test_parse_iso_date_valid_and_invalid():
|
|
assert _parse_iso_date("2026-07-05") == date(2026, 7, 5)
|
|
assert _parse_iso_date("garbage") is None
|
|
|
|
|
|
def test_percentile_basic():
|
|
"""Linear-interpolation percentile (numpy default)."""
|
|
assert _percentile([1.0, 2.0, 3.0, 4.0, 5.0], 50) == 3.0
|
|
assert _percentile([], 50) == 0.0
|
|
|
|
|
|
def test_safe_median_basic():
|
|
assert _safe_median([1.0, 2.0, 3.0]) == 2.0
|
|
assert _safe_median([]) == 0.0
|
|
|
|
|
|
def test_parse_session_name_full_format():
|
|
d, suffix = parse_session_name("20260312_190926_gencpp_sloppy")
|
|
assert d is not None
|
|
assert d.year == 2026 and d.month == 3 and d.day == 12
|
|
assert suffix == "gencpp_sloppy"
|
|
|
|
|
|
def test_parse_session_name_no_suffix():
|
|
d, suffix = parse_session_name("20260312_191301")
|
|
assert d is not None
|
|
assert d.year == 2026 and d.month == 3 and d.day == 12
|
|
assert suffix == ""
|
|
|
|
|
|
def test_parse_session_name_invalid_returns_none():
|
|
assert parse_session_name("not-a-session-name") == (None, "")
|
|
|
|
|
|
def test_parse_subagent_task_log_extracts_role_and_timestamp(tmp_path: Path):
|
|
log: Path = tmp_path / "mma_tier3-worker_task_20260611_001715.log"
|
|
log.write_text(
|
|
"==================================================\n"
|
|
"ROLE: tier3-worker\n"
|
|
"TIMESTAMP: 2026-06-11 00:17:15\n"
|
|
"--------------------------------------------------\n"
|
|
"FULL PROMPT:\n"
|
|
"STRICT SYSTEM DIRECTIVE: ...\n"
|
|
"TASK: Write a unit test.\n"
|
|
"--------------------------------------------------\n"
|
|
"RESULT:\n"
|
|
"Implemented.\n"
|
|
"==================================================\n",
|
|
encoding="utf-8",
|
|
)
|
|
result: tuple[str, datetime] | None = parse_subagent_task_log(log)
|
|
assert result is not None
|
|
role, ts = result
|
|
assert role == "tier3-worker"
|
|
assert ts == datetime(2026, 6, 11, 0, 17, 15)
|
|
|
|
|
|
def test_parse_subagent_task_log_returns_none_for_malformed(tmp_path: Path):
|
|
log: Path = tmp_path / "mma_tier3-worker_task_20260611_001715.log"
|
|
log.write_text("garbage data with no ROLE or TIMESTAMP\n", encoding="utf-8")
|
|
assert parse_subagent_task_log(log) is None
|
|
|
|
|
|
def test_find_track_for_timestamp_in_window():
|
|
tracks: list[TrackRow] = [
|
|
TrackRow(track_id="t1", init_sha="a", end_sha="b", init_date=date(2026, 3, 1),
|
|
end_date=date(2026, 3, 10), duration_days=9, commit_count=5,
|
|
files_touched=3, era_index=0, status="Completed"),
|
|
TrackRow(track_id="t2", init_sha="c", end_sha="d", init_date=date(2026, 4, 1),
|
|
end_date=date(2026, 4, 5), duration_days=4, commit_count=2,
|
|
files_touched=7, era_index=0, status="Completed"),
|
|
]
|
|
assert _find_track_for_timestamp(datetime(2026, 3, 5), tracks) == "t1"
|
|
assert _find_track_for_timestamp(datetime(2026, 4, 3), tracks) == "t2"
|
|
assert _find_track_for_timestamp(datetime(2026, 5, 1), tracks) is None
|
|
|
|
|
|
def test_compute_era_stats_aggregates_track_durations():
|
|
eras: list[EraBoundary] = [
|
|
EraBoundary(index=0, start=date(2026, 3, 1), end=None, name="early", evidence=[]),
|
|
]
|
|
tracks: list[TrackRow] = [
|
|
TrackRow(track_id="t1", init_sha="a", end_sha="b", init_date=date(2026, 3, 1),
|
|
end_date=date(2026, 3, 5), duration_days=4, commit_count=10,
|
|
files_touched=5, era_index=0, status="Completed"),
|
|
TrackRow(track_id="t2", init_sha="c", end_sha="d", init_date=date(2026, 3, 10),
|
|
end_date=date(2026, 3, 30), duration_days=20, commit_count=3,
|
|
files_touched=12, era_index=0, status="Completed"),
|
|
]
|
|
stats = compute_era_stats(eras, tracks, subagent_ops=[], commit_ops=[], sessions=[])
|
|
assert len(stats) == 1
|
|
s = stats[0]
|
|
assert s.track_count == 2
|
|
assert s.track_duration_median == 12.0
|
|
assert s.track_commits_median == 6.5
|
|
assert s.track_files_median == 8.5
|
|
|
|
|
|
def test_compute_era_stats_empty_input_returns_era_with_zeros():
|
|
eras: list[EraBoundary] = [
|
|
EraBoundary(index=0, start=date(2026, 3, 1), end=None, name="early", evidence=[]),
|
|
]
|
|
stats = compute_era_stats(eras, [], [], [], [])
|
|
assert len(stats) == 1
|
|
assert stats[0].track_count == 0
|
|
assert stats[0].track_duration_median == 0.0
|
|
|
|
|
|
def test_render_methodology_returns_string_with_section_header():
|
|
out: str = render_methodology(era_window_days=7)
|
|
assert out.startswith("# Meta-Tooling Duration Analysis")
|
|
assert "## 1. Methodology" in out
|
|
assert "7-day window" in out
|
|
|
|
|
|
def test_render_use_case_predictions_handles_empty_tracks():
|
|
out: str = render_use_case_predictions(tracks=[])
|
|
assert "Use-Case Predictions" in out
|
|
|
|
|
|
def test_build_commit_prefix_index_smoke_returns_nonempty():
|
|
"""Integration-ish test: run on real repo, expect 1000+ commits."""
|
|
eras: list[EraBoundary] = [
|
|
EraBoundary(index=0, start=date(2026, 2, 21), end=None, name="early", evidence=[]),
|
|
]
|
|
ops: list[CommitPrefixOp] = build_commit_prefix_index(eras, tracks=[])
|
|
assert len(ops) > 100, f"expected 100+ ops, got {len(ops)}"
|
|
for op in ops[:5]:
|
|
assert op.prefix in ("feat", "fix", "refactor", "perf", "test")
|
|
|
|
|
|
def test_build_subagent_task_index_smoke_returns_nonempty():
|
|
"""Integration-ish test: run on real repo, expect 1000+ tasks."""
|
|
eras: list[EraBoundary] = [
|
|
EraBoundary(index=0, start=date(2026, 2, 21), end=None, name="early", evidence=[]),
|
|
]
|
|
ops: list[SubAgentTaskOp] = build_subagent_task_index(eras, tracks=[])
|
|
assert len(ops) > 500, f"expected 500+ ops, got {len(ops)}"
|
|
tiers: set[str] = {op.tier for op in ops}
|
|
assert "tier3-worker" in tiers or "tier4-qa" in tiers
|
|
|
|
|
|
def test_build_session_index_smoke_returns_nonempty():
|
|
"""Integration-ish test: run on real repo, expect 100+ sessions."""
|
|
eras: list[EraBoundary] = [
|
|
EraBoundary(index=0, start=date(2026, 2, 21), end=None, name="early", evidence=[]),
|
|
]
|
|
sessions: list[SessionOp] = build_session_index(eras, subagent_ops=[])
|
|
assert len(sessions) > 50, f"expected 50+ sessions, got {len(sessions)}"
|
|
|
|
|
|
def test_build_track_index_smoke_returns_nonempty():
|
|
"""Integration-ish test: run on real repo, expect 100+ tracks."""
|
|
eras: list[EraBoundary] = [
|
|
EraBoundary(index=0, start=date(2026, 2, 21), end=None, name="early", evidence=[]),
|
|
]
|
|
tracks: list[TrackRow] = build_track_index(eras)
|
|
assert len(tracks) > 100, f"expected 100+ tracks, got {len(tracks)}"
|
|
for t in tracks[:3]:
|
|
assert t.init_date <= t.end_date
|
|
assert t.commit_count >= 0 |