Skip to content

v0.7.0: Session Cartographer 0.7.0

Choose a tag to compare

@github-actions github-actions released this 29 Aug 18:05
· 163 commits to main since this release

Session Cartographer 0.7.0

Primarily an attribution release. Sessions run inside a git worktree were filed under
the worktree's directory name rather than the repository's, so every throwaway agent
worktree became a phantom project that owned real history and then pointed at a dead
path once it was pruned. This release stops that happening and repairs what is already
recorded.

It also carries a search performance change and a new Explorer surface, both described
under Also in this release below.

Who needs to run the migration

Anyone who has used an agent worktree. Claude Code creates them automatically for
isolated subagents, so this is not a niche configuration — if git worktree list in
any of your repos shows entries under .claude/worktrees/, your event logs contain
phantom projects.

You do not need it if you have never run a session inside a worktree; the dry run
will simply report zero and change nothing.

Run it before any git worktree prune. The repair works by asking git to resolve
each recorded working directory back to its parent repository, and git can only answer
that while the worktree directory still exists. Pruning first destroys the mapping
permanently. On the development corpus 5,026 events were recoverable and 670 were
already past saving for exactly this reason.

Highlights

  • Hooks resolve a worktree to its parent repo. --show-toplevel returns the
    worktree directory from inside a worktree; --git-common-dir returns the main
    repo's .git in both cases, so its parent is the real project root. The new
    cartographer_project() in hooks/common.sh replaces all seven derivation sites
    across five hooks, including the two FILE_REPO variants in log-tool-use.sh.
  • A migration that repairs the existing corpus.
    scripts/migrate-project-attribution.js repoints project in place and records
    project_repointed_from so the edit is auditable. cwd and git_branch are
    accurate history and are never rewritten.
  • Three edge cases handled, each of which a naive implementation gets wrong: git
    before 2.31 has no --path-format; a bare repository would otherwise resolve to the
    name of its parent directory; and a non-repo directory still falls back to its own
    basename.

Also in this release

  • Search stopped scaling with corpus size. bm25-search.awk populated df[] for
    every token in the corpus on every query. Pass 1 now gathers document frequencies for
    the query's tokens only, and a byte-level grep pass narrows pass 2 to rows containing
    at least one normalized query token before any scoring runs. Guardrail tests cover
    both this path and the Explorer's JSONL read, so a change that reintroduces a
    whole-corpus pass fails rather than quietly getting slower.
  • Explorer gained Internals, a system-observation surface. The Timeline explains the
    chronology of human work; Internals explains how the system itself behaved. The read
    runs in a worker behind an aggregator so it never blocks the API, and the client
    degrades to stale data rather than a spinner when an aggregate is slow. See
    docs/INTERNALS.md, and docs/TURBO_MODE_SPEC.md for a draft of utility-first
    recall.

Neither needs any migration or action on upgrade.

Upgrading

node scripts/migrate-project-attribution.js            # dry run — reports, changes nothing
node scripts/migrate-project-attribution.js --apply

The dry run prints, per log, how many events would be repointed and how many reference
a worktree that no longer exists, followed by the phantom projects ranked by event
count. Nothing is written until you pass --apply.

Order matters the same way it did in 0.6.1: upgrade the hooks first so new events are
written with the correct project, then migrate. The migration is idempotent and safe to
re-run; a second pass reports 0 event(s) repointed.

Safety

session-milestones.jsonl takes live appends from other sessions, so the migration is
built for that rather than against it. It backs up every file it touches before writing,
carries across anything appended during the pass instead of truncating it, and verifies
by event-id set comparison rather than line counts — a concurrent append can
otherwise mask a loss that a count check would pass. If any event id goes missing it
restores from the backup and exits nonzero.

It only repoints a record carrying the bug's exact signature, where project equals the
basename of the recorded cwd. Events whose project came from a different code path are
left alone. Unparseable lines survive verbatim.

What this does not fix

Events whose worktree has already been pruned cannot be recovered — the directory that
would have identified the parent repository is gone, and guessing would be worse than
leaving the record honest. The dry run counts them separately so you can see the scale
of what was lost before the fix landed.

Full implementation detail is in CHANGELOG.md.