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 scratchpad, every peer session's scratchpad, and the agent homes
(`~/.claude`, `~/.agents`, `~/.codex`) for skills, commands, agents, hooks (`~/.claude`, `~/.agents`, `~/.codex`) for skills, commands, agents, hooks
and rules the skills repository does not ship. It keeps scripts, tests and 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 dropped candidates return only when their content changes; `later` returns
every time. 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 r"(secret|token|credential|passw|auth|\.env$|id_[a-z0-9]+$|\.pem$|\.key$)", re.IGNORECASE
) )
MAX_BYTES = 1_000_000 MAX_BYTES = 1_000_000
MAX_DEPTH = 1
REPO_MARKERS = {".git", "roles", "plugins", "pyproject.toml", "package.json", "Makefile"}
HOME_SOURCES = { HOME_SOURCES = {
".claude/skills": "skill", ".claude/skills": "skill",
".agents/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]: def scratch_candidates(root: Path, source: str, owner: str) -> list[dict]:
found = [] found = []
for path in sorted(p for p in root.rglob("*") if p.is_file()): for current, dirs, files in os.walk(root):
kind = file_kind(path) here = Path(current)
if kind: depth = len(here.relative_to(root).parts)
found.append({"source": source, "owner": owner, "kind": kind, "path": str(path)}) if depth and REPO_MARKERS & {*dirs, *files}:
return found 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]: 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 / "auth_token.py", "secret")
self._write(self.own / "big.py", "x" * 1_000_001) self._write(self.own / "big.py", "x" * 1_000_001)
self._write(self.peer / "helper.sh", "echo hi") 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"): for name in ("kvb-x", "caveman", "custom"):
self._write(self.home / ".claude" / "skills" / name / "SKILL.md", name) self._write(self.home / ".claude" / "skills" / name / "SKILL.md", name)
self._write(self.home / ".codex" / "rules" / "default.rules", "allow") self._write(self.home / ".codex" / "rules" / "default.rules", "allow")
@@ -78,6 +82,7 @@ class TestTranscend(unittest.TestCase):
"probe.py": ("own", "self", "script"), "probe.py": ("own", "self", "script"),
"test_probe.py": ("own", "self", "test"), "test_probe.py": ("own", "self", "test"),
"helper.sh": ("peer", "Peer", "script"), "helper.sh": ("peer", "Peer", "script"),
"nested.py": ("peer", "Peer", "script"),
"custom": ("home", "operator", "skill"), "custom": ("home", "operator", "skill"),
"default.rules": ("home", "operator", "rule"), "default.rules": ("home", "operator", "rule"),
}, },