fix(transcend): skip repository copies in scratchpads

A scan on the real host offered 4276 candidates, 4253 of them files of two repository copies in one peer's scratchpad. scratch_candidates now walks with os.walk, skips any directory holding .git, roles, plugins, pyproject.toml, package.json or a Makefile, and descends at most one level below a scratchpad; the real scan drops to 59 candidates. test_transcend adds a nested helper that stays, a deeper one and a repository copy that drop out (negative control against the unfiltered scan fails).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kevin Veen-BirkenbachandClaude Opus 5.5 committed 2026-11-03 17:57:08 +01:00
1 parent 194f5e28bd
commit 3e2f7a7ddb
3 files changed
+25 -6

No files matched your search

+3 -1
View File
@@ -19,7 +19,9 @@ transcend.py mark --state <same> <path> carried|dropped|later
scratchpad, every peer session's scratchpad, and the agent homes
(`~/.claude`, `~/.agents`, `~/.codex`) for skills, commands, agents, hooks
and rules the skills repository does not ship. It keeps scripts, tests and
skills, and skips files named like secrets and files over 1 MB. Carried or
skills at most one directory below a scratchpad, and skips files named like
secrets, files over 1 MB, and repository copies (a directory holding `.git`,
`roles`, `plugins`, `pyproject.toml`, `package.json` or a `Makefile`). Carried or
dropped candidates return only when their content changes; `later` returns
every time.
+17 -5
View File
@@ -22,6 +22,8 @@ SECRET_NAME = re.compile(
r"(secret|token|credential|passw|auth|\.env$|id_[a-z0-9]+$|\.pem$|\.key$)", re.IGNORECASE
)
MAX_BYTES = 1_000_000
MAX_DEPTH = 1
REPO_MARKERS = {".git", "roles", "plugins", "pyproject.toml", "package.json", "Makefile"}
HOME_SOURCES = {
".claude/skills": "skill",
".agents/skills": "skill",
@@ -74,11 +76,21 @@ def session_names(home: Path) -> dict[str, str]:
def scratch_candidates(root: Path, source: str, owner: str) -> list[dict]:
found = []
for path in sorted(p for p in root.rglob("*") if p.is_file()):
kind = file_kind(path)
if kind:
found.append({"source": source, "owner": owner, "kind": kind, "path": str(path)})
return found
for current, dirs, files in os.walk(root):
here = Path(current)
depth = len(here.relative_to(root).parts)
if depth and REPO_MARKERS & {*dirs, *files}:
dirs.clear()
continue
if depth >= MAX_DEPTH:
dirs.clear()
for name in files:
kind = file_kind(here / name)
if kind:
found.append(
{"source": source, "owner": owner, "kind": kind, "path": str(here / name)}
)
return sorted(found, key=lambda item: item["path"])
def shipped(skills_repo: Path) -> set[str]:
+5
View File
@@ -40,6 +40,10 @@ class TestTranscend(unittest.TestCase):
self._write(self.own / "auth_token.py", "secret")
self._write(self.own / "big.py", "x" * 1_000_001)
self._write(self.peer / "helper.sh", "echo hi")
self._write(self.peer / "probe" / "nested.py", "print(2)")
self._write(self.peer / "probe" / "deep" / "too_deep.py", "print(3)")
self._write(self.peer / "copy" / "pyproject.toml", "[project]")
self._write(self.peer / "copy" / "copied.py", "print(4)")
for name in ("kvb-x", "caveman", "custom"):
self._write(self.home / ".claude" / "skills" / name / "SKILL.md", name)
self._write(self.home / ".codex" / "rules" / "default.rules", "allow")
@@ -78,6 +82,7 @@ class TestTranscend(unittest.TestCase):
"probe.py": ("own", "self", "script"),
"test_probe.py": ("own", "self", "test"),
"helper.sh": ("peer", "Peer", "script"),
"nested.py": ("peer", "Peer", "script"),
"custom": ("home", "operator", "skill"),
"default.rules": ("home", "operator", "rule"),
},