Files
Juan DenisandClaude Fable 5 c803ee5012 fix(census): measure only tracked files — the instruments count what ships
The raw-subprocess census and the thread-ownership guard walked the
filesystem under backend/app, which on a dev box also holds *installed*
extension copies under app/plugins/ that git does not track. The census
therefore measured 28 on dev machines but 24 on CI's clean checkout — four
sites of invisible ceiling slack, a stale thread classification for the
locally-installed analytics extension, and a red migration-inventory
freshness test on every CI run since the range landed.

Both instruments now intersect their walk with git ls-files (falling back
to walking everything when git cannot answer), the analytics thread entry
is removed (extension repos own their own threads), the ceiling ratchets
down 28 -> 24, and the inventory is regenerated. Proving test:
test_untracked_files_are_not_counted plants an untracked file with a raw
call inside app/ and asserts the census does not see it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 10:06:38 -04:00

45 lines
1.7 KiB
Python

"""Scope tree-measuring instruments to the files that ship with the repo.
The censuses and structural guards measure ``backend/app`` by walking the
filesystem — but a dev box's ``app/plugins/`` also holds *installed* extension
copies that are not tracked in git (only the builtin extensions are). A walk
that counts those measures the machine, not the product: the raw-subprocess
ceiling picked up 4 call sites from locally-installed extensions that CI's
clean checkout can never see, which is exactly the silent-slack failure mode
the ceilings exist to prevent.
``tracked_py_files()`` returns the set of git-tracked ``.py`` paths under a
root, so an instrument can skip everything else. When git is unavailable it
returns ``None`` and callers fall back to walking everything — measuring too
much is recoverable; measuring nothing is not.
"""
import os
import subprocess
def tracked_py_files(root):
"""Absolute, ``os.path.normcase``-normalised paths of git-tracked ``.py``
files under *root*, or ``None`` when git cannot answer."""
try:
proc = subprocess.run(
['git', 'ls-files', '-z', '--', '.'],
cwd=root, capture_output=True, text=True, timeout=30,
)
except (OSError, subprocess.TimeoutExpired):
return None
if proc.returncode != 0:
return None
return {
os.path.normcase(os.path.abspath(os.path.join(root, rel)))
for rel in proc.stdout.split('\0')
if rel.endswith('.py')
}
def is_tracked(path, tracked):
"""True when *path* is in *tracked*, or when there is no filter."""
if tracked is None:
return True
return os.path.normcase(os.path.abspath(path)) in tracked