Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions tests/guards/test_debt_ratchet.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ def test_a_new_store_lock_call_fails_on_its_own_file_with_its_line(repo):
" with store.locked():\n pass\n"})
status, report = repo.compare(base, head, StoreLockCalls)
assert status == 1
grown = StoreLockCalls.key(f"{repo.root}/other.py")
assert report["delta"] == {StoreLockCalls.key(f"{repo.root}/turns.py"): -1, grown: 1}
grown = StoreLockCalls.at(f"{repo.root}/other.py").text
assert report["delta"] == {StoreLockCalls.at(f"{repo.root}/turns.py").text: -1, grown: 1}
assert report["found"] == {grown: [{"path": f"{repo.root}/other.py", "line": line}
for line in (2, 4)]}

Expand All @@ -173,6 +173,7 @@ def __init__(self, path: Path, root: str):
self.path = path
self.root = root
self.git("init", "-q")
self.git("remote", "add", "origin", str(SOURCE))

def git(self, *args: str) -> str:
return subprocess.check_output(
Expand Down Expand Up @@ -377,7 +378,6 @@ def test_a_done_phase_fails_the_change_that_breaks_it(tmp_path: Path) -> None:
objects = subprocess.check_output(["git", "-C", str(SOURCE), "rev-parse", "--path-format=absolute",
"--git-common-dir"], text=True).strip()
(tmp_path / ".git/objects/info/alternates").write_text(f"{objects}/objects\n")
repo.git("remote", "add", "origin", str(SOURCE))
owned = "class Owned:\n pass\n"
base = repo.commit({"agent_comms/owned.py": owned})
head = repo.commit({"agent_comms/owned.py": owned + "\n\ndef owns(value):\n"
Expand Down
36 changes: 25 additions & 11 deletions tools/debt_ratchet.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ def blocks(cls, delta: Counts) -> bool:

@classmethod
def grew(cls, key: MeasureCount, grown: int) -> str:
"""The line reporting one count's growth."""
return f"grew {key.text} +{grown}"
"""The line reporting one count's growth; the count words it."""
return key.grew(grown)

@classmethod
def run_by(cls) -> type[Measure]:
Expand Down Expand Up @@ -226,6 +226,10 @@ def warning(self, text: str) -> str:
"""A check annotation for this count; a total annotates no file."""
return f"::warning::{text}"

def grew(self, grown: int) -> str:
"""The line saying this count grew."""
return f"grew {self.text} +{grown}"


@dataclass(frozen=True)
class FileCount(MeasureCount):
Expand Down Expand Up @@ -259,6 +263,21 @@ def text(self) -> str:
return f"{super().text}::{self.name}"


@dataclass(frozen=True)
class PhaseSiteCount(MeasureCount):
"""One site where a done plan phase's evidence fails."""

phase: type[PlanPhase]
site: str

@property
def text(self) -> str:
return f"{super().text}:{self.phase.__name__}::{self.site}"

def grew(self, grown: int) -> str:
return f"done plan phase {self.phase.__name__} no longer holds: {self.site}"


# One revision's counts, each under the record of what it counts.
type Counts = dict[MeasureCount, int]

Expand Down Expand Up @@ -2604,32 +2623,27 @@ class DonePhaseBroken(Measure):
@classmethod
def parts(cls, repo: Path, base: str, head: str, changed: set[str],
root: str) -> tuple[Callable[[], object], ...]:
declared = Path(sys.modules[PlanPhase.__module__].__file__ or "").resolve()
declared = Path(inspect.getfile(PlanPhase)).resolve()
if root != f"{declared.relative_to(REPOSITORY).parts[0]}/":
return ()
return tuple(partial(cls.failing, repo, revision(repo, ref)) for ref in (base, head))

@classmethod
def combine(cls, results: list, repo: Path, base: str, head: str, changed: set[str],
root: str) -> tuple[dict[str, int], dict[str, int]]:
root: str) -> tuple[Counts, Counts]:
"""A failing pull request pays for reading its sites; a passing one never reads them."""
if not results:
return {}, {}
before, after = results
reading = PlanReading((), MainTree(Repo.of(repo), revision(repo, head)))
broken = {
cls.key(f"{phase.__name__}::{site}"): 1
broken: Counts = {
PhaseSiteCount(cls, phase, site): 1
for phase in PlanPhase.members_with(PlanPhase)
if phase.__name__ in after - before
for site in phase.evidence.sites(reading) or (reading.describe(phase.evidence),)
}
return dict.fromkeys(broken, 0), broken

@classmethod
def grew(cls, key: str, grown: int) -> str:
phase, _, site = key.partition(":")[2].partition("::")
return f"done plan phase {phase} no longer holds: {site}"

@classmethod
def failing(cls, repo: Path, commit: str) -> frozenset[str]:
"""The name of each phase not done at a commit."""
Expand Down
Loading