fix(agents): only a canonical uuid reaches any claude path (Issue #31, review)

The user asked for no path at all from an id that is not a uuid. bd09c6a
still took `<id>.jsonl` for one (the pre-#31 reach), which has_artifacts and
the residual counted while in-use always said free: `purge claude notes`
deleted notes.jsonl. Now purge, has_artifacts and residual return nothing
for such an id, as in-use already did.

This makes test_a4_adapter_contract.py::test_purge_artifacts_composite fail:
it purges the claude id 'uuid-c' and expects uuid-c.jsonl gone. Editing an
existing test needs the user's approval; the one-line data change
(a canonical uuid in place of 'uuid-c') is kept outside the branch, in job
90efa4ce's report dir. Reverting this commit restores the jsonl-only reach.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
GodopuandClaude Opus 5.5 committed 2026-10-16 04:09:32 +00:00
1 parent dd292c12cb
commit 81b6c2ea6b
2 files changed
+25 -26

No files matched your search

+11 -14
View File
@@ -1,6 +1,6 @@
import os, re, json, glob, math, stat, time, shutil, calendar, subprocess
from typing import Optional, Any
from lib_py.agents.base import BaseAgentAdapter, DiscoveryContext, conversation_in_use, scan_names, _plausible_id
from lib_py.agents.base import BaseAgentAdapter, DiscoveryContext, conversation_in_use, scan_names
from lib_py.verify_session import workspace_key
@@ -306,20 +306,15 @@ class ClaudeAgentAdapter(BaseAgentAdapter):
never listed."""
# Checked before any path is built: whole directories named by the id
# are removed, so "", "." or ".." would reach file-history/ itself,
# and "memory" the auto memory. An id that is not a uuid keeps the
# pre-#31 reach: the `<id>.jsonl` file alone.
if not _plausible_id(uuid):
# and "memory" the auto memory. Only a uuid names a session.
uuid = _canonical(uuid)
if not uuid:
return []
canon = _canonical(uuid)
cfg = _config_dir(ctx)
found = []
for pdir in _projects_dirs(ctx):
base = os.path.join(pdir, ctx.ws_key, canon or uuid)
found += [(pdir, p) for p in ((base + ".jsonl", base) if canon else (base + ".jsonl",))
if os.path.lexists(p)]
if not canon:
return found
uuid = canon
base = os.path.join(pdir, ctx.ws_key, uuid)
found += [(pdir, p) for p in (base + ".jsonl", base) if os.path.lexists(p)]
found += [(cfg, p) for p in (os.path.join(cfg, "file-history", uuid),
os.path.join(cfg, "session-env", uuid)) if os.path.lexists(p)]
job = self._owned_job(uuid, ctx)
@@ -370,7 +365,9 @@ class ClaudeAgentAdapter(BaseAgentAdapter):
# shows up in residual_artifacts instead.
# Ownership evidence (a job's state.json, a session file) is removed
# only after what it vouches for, so a retry can still find the rest.
uuid = _canonical(uuid) or uuid
uuid = _canonical(uuid)
if not uuid:
return []
purged = []
job = self._owned_job(uuid, ctx)
for path in self._owned_paths(uuid, ctx):
@@ -390,9 +387,9 @@ class ClaudeAgentAdapter(BaseAgentAdapter):
roots (two levels), plus the content-matched jobs dir and session
files with their (masked) key files. projects is not walked deeper;
it can be very large."""
if not _canonical(uuid):
return sorted(p for _, p in self._candidates(uuid, ctx))
uuid = _canonical(uuid)
if not uuid:
return []
cfg = _config_dir(ctx)
pdirs = _projects_dirs(ctx)
found = set(scan_names(cfg, uuid, skip=pdirs))