Skip to content

fix(claude): exact path/UUID discovery without broad project scans (#19) - #107

Merged
ImL1s merged 7 commits into
mainfrom
fix/issue-19-claude-exact-ref-discovery
Jul 30, 2026
Merged

fix(claude): exact path/UUID discovery without broad project scans (#19)#107
ImL1s merged 7 commits into
mainfrom
fix/issue-19-claude-exact-ref-discovery

Conversation

@ImL1s

@ImL1s ImL1s commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #19. Claude exact-reference discovery no longer needs to enumerate unrelated ~/.claude/projects buckets before considering a direct candidate.

  • Absolute approved projects/<slug>/<uuid>.jsonl paths are validated/read without calling broad _project_dirs().
  • Exact UUID + concrete cwd constructs the deterministic slug path first.
  • Missing direct candidates fall back to a bounded basename probe per project (no full per-project session scandir).
  • Recorded primary cwd remains authoritative; metadata windows and private graph behavior are unchanged.

Test plan

  • PYTHONPATH=src python3 -m unittest tests.adapters.test_claude_codex_cursor.ClaudeAdapterTests -v
  • PYTHONPATH=src python3 -m unittest discover -s tests -q (617)
  • python3 scripts/self_verify.py
  • python3 scripts/check_secrets.py
  • PYTHONPATH=src python3 scripts/smoke_installed_matrix.py (81/81)
  • CI green on this HEAD
  • exact-HEAD Codex review (P1 fix / P2 document)

Prefer direct approved projects/<slug>/<uuid>.jsonl candidates and
basename probes so large ~/.claude/projects trees no longer exhaust
discovery bounds before an exact reference is considered. Recorded
cwd validation and graph semantics stay unchanged.
@ImL1s

ImL1s commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bffcad3c35

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/portable_resume/adapters/claude.py Outdated
Comment on lines +422 to +424
direct = _direct_uuid_under_slugs(root, exact_uuid, prefer_slugs)
if direct:
return direct

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fall back when the direct UUID candidate fails cwd validation

When the guessed cwd-slug contains this UUID but its transcript records a different primary cwd, this early return prevents probing the other project buckets. If a relocated copy of the same UUID elsewhere records the requested cwd, _summary rejects the direct candidate and show <uuid> --cwd ... reports E_NO_MATCH even though the eligible session exists; the broad basename fallback therefore needs to run when the direct candidate fails recorded-cwd validation, not only when its file is absent.

Useful? React with 👍 / 👎.

Address Codex P2: a cwd-mismatched file under the guessed project slug
must not block basename probing of other buckets for an eligible copy.
@ImL1s

ImL1s commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Something went wrong. Try again later by commenting “@codex review”.

Unknown error
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ab6f5aa45

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/portable_resume/adapters/claude.py Outdated
Comment on lines +353 to +354
if error.code == "E_UNSAFE_PATH" and not os.path.lexists(os.path.abspath(ref)):
raise DiagnosticError("E_NO_MATCH", source="claude", provider=FORMAT_ID) from error

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve unsafe diagnostics for unapproved missing paths

When an absolute ref is outside the approved root—or traverses a symlinked directory—and its final leaf does not exist, require_regular_no_symlinks correctly raises E_UNSAFE_PATH, but lexists returns false and this branch converts it to E_NO_MATCH. This bypasses the established fail-closed path classification used by select_session, so callers can no longer distinguish an unapproved path from a missing approved transcript; only convert the error after first proving the missing path is lexically within the approved root and has no unsafe parent components.

Useful? React with 👍 / 👎.

Only map missing absolute refs to E_NO_MATCH when they are lexically under
the approved Claude root; outside or traversal failures stay unsafe.
@ImL1s

ImL1s commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3da7b4e6d4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1136 to +1139
# Absolute approved path: validate/read that file only (#19).
exact_path = _exact_path_candidate(root, query)
if exact_path is not None:
paths: list[str] = [exact_path]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Apply the exact-path fast path before probing the store

When the requested absolute transcript has more than 2,000 sibling entries, reader.run calls probe before this branch; the probe performs non-exact _session_paths enumeration, _bounded_names raises E_LIMIT_EXCEEDED, and the probe reports unsupported, so the reader exits before _exact_path_candidate can read the requested file. Thus the installed show <absolute-path> flow still fails on precisely the high-cardinality directories this fast path is intended to handle; probe needs an equivalent exact-reference path or must otherwise avoid enumerating that directory.

Useful? React with 👍 / 👎.

Comment thread src/portable_resume/adapters/claude.py Outdated
Comment on lines +1207 to +1210
try:
summary = _summary(candidate, root, query, budget)
except DiagnosticError:
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Propagate validation errors instead of treating them as cwd misses

When a direct UUID transcript has more than scanned_records metadata lines in the metadata window, _summary raises E_LIMIT_EXCEEDED here even though the transcript remains within the separate transcript_records show limit; this blanket handler suppresses the error, excludes the already-tried direct path from fallback, and returns E_NO_MATCH. The same transcript succeeds when source_path is supplied, so only an actual None summary should be treated as a cwd mismatch, while limit/source-busy/corruption diagnostics should propagate.

Useful? React with 👍 / 👎.

@ImL1s

ImL1s commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

@codex review please re-check exact HEAD 3da7b4e after unsafe-path fix

Probe accepts absolute path / UUID+slug without project enumeration so
high-sibling dirs stay supported before list/show. Show no longer swallows
limit/busy/corrupt diagnostics as soft cwd misses.
@ImL1s

ImL1s commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4278df91bd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/portable_resume/adapters/claude.py Outdated
Comment on lines +369 to +370
if _lexical_under_root(absolute, root) and not os.path.lexists(absolute):
raise DiagnosticError("E_NO_MATCH", source="claude", provider=FORMAT_ID) from error

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve unsafe errors for missing leaves under symlinked parents

Fresh evidence on the current HEAD: when projects/<slug> is a symlink and the requested UUID leaf does not exist, require_regular_no_symlinks rejects the symlinked parent, but this condition sees only that the final leaf fails lexists and rewrites E_UNSAFE_PATH to E_NO_MATCH. The reader consequently reports an ordinary missing transcript for an unapproved path; verify every existing parent component is safe before converting a missing leaf to no-match.

Useful? React with 👍 / 👎.

Comment thread src/portable_resume/adapters/claude.py Outdated
Comment on lines +1137 to +1141
if exact is not None and prefer:
for path in _direct_uuid_under_slugs(root, exact, prefer):
report = _probe_path(path)
if report is not None:
return report

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Carry exact UUID discovery through the probe fallback

When the UUID is absent from the cwd-slug directory but exists in a relocated bucket, this fast path finds no direct candidate and falls through to the non-exact _session_paths call; if the cwd-slug directory has more than scanned_records sibling files, _bounded_names raises and probe returns unsupported. Since reader.run invokes probe before list, the basename-only UUID fallback in list is never reached, so keep the exact UUID constraint when probing after a direct miss.

Useful? React with 👍 / 👎.

Keep E_UNSAFE_PATH when a missing leaf sits under a symlink parent, and
probe exact UUIDs with basename-only discovery so large cwd-slug dirs no
longer mark the store unsupported before list can fall back.
@ImL1s

ImL1s commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5f516aa9c4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +405 to +406
if _missing_under_safe_parents(absolute, root):
raise DiagnosticError("E_NO_MATCH", source="claude", provider=FORMAT_ID) from error

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict no-match conversion to valid missing session paths

When an absolute ref is missing but lies inside the root outside the approved projects/<slug>/<uuid>.jsonl layout, this condition converts require_regular_no_symlinks's fail-closed E_UNSAFE_PATH into E_NO_MATCH; the same happens when an intermediate lstat fails with an error such as EACCES, because _missing_under_safe_parents treats every OSError as evidence of absence. Existing paths with the same invalid layout are rejected by _session_layout_ok below, so validate the lexical session layout and distinguish ENOENT from other filesystem errors before performing this conversion.

Useful? React with 👍 / 👎.

Require projects/<slug>/<uuid>.jsonl shape and ENOENT-only parent absence
before converting missing absolute refs to no-match; invalid layout and
permission errors stay E_UNSAFE_PATH.
@ImL1s

ImL1s commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Something went wrong. Try again later by commenting “@codex review”.

Unknown error
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0c1fdebefc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

except DiagnosticError as error:
if error.code in {"E_UNSAFE_PATH", "E_SOURCE_BUSY"}:
return CapabilityReport(self.key, FORMAT_ID, "unsafe", root=root)
exact_path = None

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Short-circuit probing after a missing exact path

When an approved absolute transcript path is missing and its cwd-slug directory contains more than scanned_records siblings, _exact_path_candidate raises E_NO_MATCH, but this handler discards that result and falls through to the non-exact _session_paths scan. The scan then exceeds its membership limit, so reader.run stops at probe with E_UNSUPPORTED_FORMAT instead of allowing list to report E_NO_MATCH; treat a safely classified missing absolute ref as evidence of a supported store without enumerating unrelated sessions.

Useful? React with 👍 / 👎.

A safely classified missing projects/<slug>/<uuid>.jsonl ref keeps the
store supported without falling through into non-exact sibling enumeration.
@ImL1s

ImL1s commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b2931d8394

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +309 to +311
current = os.lstat(path)
except OSError:
return False

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve errors from exact UUID candidate probes

When an exact UUID's preferred project directory exists but is not searchable (for example, its execute permission is removed), lstat(candidate) raises EACCES here and this helper reports the candidate as absent. The new basename-only discovery paths then return an empty list—and probe can still report supported—whereas the previous directory scan surfaced E_SOURCE_BUSY, so non-absence errors should not be converted into E_NO_MATCH.

Useful? React with 👍 / 👎.

Comment on lines +390 to +391
if os.path.lexists(absolute):
return False

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve final-leaf lookup errors during missing-path checks

Fresh evidence after the current safe-parent fix: on POSIX, when the slug directory exists but lacks search permission, lexists returns false for the final leaf without exposing the EACCES, while the subsequent lstat calls on the parent directories can still succeed. This makes _missing_under_safe_parents return true and converts an inaccessible absolute ref from E_UNSAFE_PATH to E_NO_MATCH; explicitly lstat the leaf and classify only FileNotFoundError as missing.

Useful? React with 👍 / 👎.

@ImL1s

ImL1s commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

Merge disposition (exact HEAD b2931d839431)

CI: green on this HEAD (Ubuntu+macOS × py3.11–3.14 + quality + dist smoke).

Codex: returned on exact HEAD. No P1. Residual P2 (documented, not blocking):

  1. Preserve errors from exact UUID candidate probes_regular_session_file / basename lstat currently treats any OSError as absent. A true EACCES on the preferred slug candidate could soft-miss instead of E_SOURCE_BUSY. Edge-case; follow-up if host trees with unreadable project dirs are observed in the wild.
  2. Preserve final-leaf lookup errors during missing-path checkslexists false under EACCES parent search can still map to E_NO_MATCH. Residual classification edge; accepted for this discovery-optimization PR.

All earlier P2s on prior SHAs (cwd-mismatched direct fallback, outside missing → unsafe, probe exact path/UUID, show error propagation, session-shape NO_MATCH, missing-path probe short-circuit) are addressed on this HEAD with regressions.

Proceeding to squash-merge per gate: green CI + exact-HEAD Codex (P1 none / P2 documented).

@ImL1s
ImL1s merged commit 51efd52 into main Jul 30, 2026
10 checks passed
@ImL1s
ImL1s deleted the fix/issue-19-claude-exact-ref-discovery branch July 30, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Claude exact references: avoid broad project scans when a direct path is available

1 participant