Skip to content

Reach projects under dotted paths, and let --cwd name the scope - #13

Merged
UnbreakableMJ merged 1 commit into
mainfrom
fix-mangle-cwd-and-ingest-scope
Aug 25, 2026
Merged

Reach projects under dotted paths, and let --cwd name the scope#13
UnbreakableMJ merged 1 commit into
mainfrom
fix-mangle-cwd-and-ingest-scope

Conversation

@UnbreakableMJ

Copy link
Copy Markdown
Contributor

Two defects that both made ingest lie quietly rather than fail. Found while working out how to bulk-import every session on a machine — both block that directly.

1. A dotted path was unreachable, and said NOT_FOUND

mangle_cwd replaced only /. The harness replaces more. Its own function, from the Claude Code bundle:

function tl(e){ let t = e.replace(/[^a-zA-Z0-9\-_]/g,"-"); return t===""?"unknown":t }

So a dot becomes a dash too, and the two spellings diverge:

real:    /spacecraft-software/construct/.claude/worktrees/peaceful-jones-da993c
engram:  ...construct-.claude-worktrees-...   ← looked here
ondisk:  ...construct--claude-worktrees-...   ← harness wrote here

Engram reported NOT_FOUND, which reads as "no such session" rather than "I spelled the directory wrong". Every worktree Claude Code creates lives under .claude/worktrees/, so the blind spot grows with use.

Verified against all 17 project directories on this machine and 46 OpenClaude ones — the new rule reproduces every name exactly.

The test planters carried a copy of the same bug

This mattered more than it looks. plant_claude_transcript and plant_openclaude_transcript each had their own .replace('/', "-"), and a TempDir path contains .tmpXXXX — so after the fix they would have planted into a directory the reader no longer reads, failing every ingest test for a reason unrelated to what they test. Both now call one helper that mirrors production, with a comment explaining why it must.

2. --cwd chose the transcripts but never the scope

ingest --cwd read another project's sessions while scope still resolved from the process's directory:

--cwd /spacecraft-software/standard  →  scope=engram  origin=git-root

Importing 33 projects from one terminal filed every one of them under whichever scope that terminal was in — and the response said scope_origin: "git-root" each time, so the output looked entirely correct while the data was mis-filed.

rules::resolve_scope_in takes the directory as an argument; resolve_scope now delegates to it, so every other caller is unchanged. Explicit --scope still wins.

--cwd /spacecraft-software/standard              →  scope=standard  origin=git-root
--cwd /spacecraft-software/vault                 →  scope=vault     origin=git-root
--cwd /spacecraft-software/standard --scope foo  →  scope=foo       origin=explicit

Verified on real data

The worktree that returned NOT_FOUND now ingests:

→ scope=peaceful-jones-da993c  inserted=12  sessions=1

Gates

fmt · clippy -D warnings · 264 tests · REUSE 3.3 · makeinfo clean

🤖 Generated with Claude Code

https://claude.ai/code/session_016i16R4GhdSffsboRYq97Fs

Two defects that both made `ingest` lie quietly rather than fail.

`mangle_cwd` replaced only `/`. The harness replaces every character outside
`[A-Za-z0-9\-_]` — its own function is `e.replace(/[^a-zA-Z0-9\-_]/g,"-")` with
`""` mapping to `unknown` — so a dot becomes a dash too. Engram therefore looked
for `…construct-.claude-worktrees-x` where Claude Code had written
`…construct--claude-worktrees-x`, and reported NOT_FOUND, which reads as "no
such session" rather than "I spelled the directory wrong". Every worktree
Claude Code creates lives under `.claude/worktrees/`, so this grew with use.

The test planters carried a copy of the same wrong rule, which mattered more
than it looks: a TempDir path contains `.tmpXXXX`, so after the fix they would
have planted into a directory the reader no longer reads. Both now call one
helper that mirrors production, with a comment saying why.

`ingest --cwd` chose which transcripts to read but never the scope, which still
resolved from the process's directory. Importing thirty-three projects from one
terminal filed every one of them under whichever scope that terminal was in,
and the response said `scope_origin: "git-root"` each time — correct-looking
output for silently mis-filed data. `rules::resolve_scope_in` takes the
directory as an argument; `resolve_scope` now delegates to it. Explicit
`--scope` still wins.

Verified on the real machine: the worktree that returned NOT_FOUND now yields
12 turns, and `--cwd /spacecraft-software/vault` files into `vault`.

Gates: fmt, clippy -D warnings, 264 tests, REUSE 3.3, makeinfo clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016i16R4GhdSffsboRYq97Fs
@UnbreakableMJ
UnbreakableMJ merged commit 6a08063 into main Aug 25, 2026
5 checks passed
@UnbreakableMJ
UnbreakableMJ deleted the fix-mangle-cwd-and-ingest-scope branch August 25, 2026 19:44

@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: 29e4029917

ℹ️ 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/transcript/mod.rs
Comment on lines +283 to +284
.to_string_lossy()
.chars()

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 Match JavaScript’s UTF-16 replacement for astral characters

When the working-directory path contains a non-BMP character such as an emoji, iterating with Rust chars() replaces it with one dash, while Claude Code’s non-u JavaScript regex processes its two UTF-16 surrogate code units separately and produces two dashes. For example, Claude Code maps /tmp/😀 to -tmp---, but this function returns -tmp--, so the transcript directory is again reported as missing; iterate over UTF-16 code units (and update the mirrored test helper) to reproduce the harness exactly.

AGENTS.md reference: AGENTS.md:L261-L261

Useful? React with 👍 / 👎.

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.

1 participant