worktree-identity — naming fix + branch consolidation plan¶
Status: BLOCKED on consolidation. Design complete (below). Do NOT implement the naming fix on a feature branch until the repo is consolidated onto master, or you add a 6th divergent branch.
Why sessions/worktrees don't name themselves (root causes)¶
-
No title applier. The pipeline is: UserPromptSubmit hook registers the session + injects the
SESSION-IDENTITYdirective → the model runsworktree-identity update(writes the registry) → nothing pushes the title to the UI. The only thing that renames a session is the CCD MCP toolset_session_title, a session cannot rename itself, and no daemon/peer calls it. Result: the registry is correct but UI titles stay stale. Only 2 of ~30 live sessions ever got aWT-…title (hand-applied once).set_session_titlealso always prompts the user — so a fully-silent auto-renamer is impossible by design; the best achievable is a peer/scheduled agent that proposes renames from a computed diff. -
Ephemeral keying. Session entries key on
session_id(HookHandler.Handle), which regenerates per PC restart, so restart orphans every WT-id→ticket mapping and new sessions register as"unnamed". NOTE: in current usage every session'scwdis the non-git main repos root (C:\Users\fives\source\repos), so pure path-keying would collapse them all to one id — path capture only helps sessions actually launched inside a per-worktree dir.
Design (build on consolidated master)¶
BUG 2 — applier (load-bearing)¶
- New verb
sync-titles: reads a live-sessions JSON on stdin/--sessions <file>([{sessionId,title}], from CCDlist_sessions), outputs a rename manifest[{sessionId,currentTitle,desiredTitle}]for entries where the entry is named (Description != "unnamed") AND live title !=TitleFormatter.Format(entry). - The manifest is consumed by an orchestrator/scheduled Claude session that calls
set_session_titleper row (the only non-headless step: MCP call + user confirm). Wire a scheduled task or fold into an existing coordinator loop so it runs periodically.
BUG 1 — path-aware keying (collision-safe)¶
- Add
WorktreePath,Branch,LastHeartbeatUtctoRegistryEntry. Program.cs hookresolvescwd→git -C <cwd> rev-parse --show-toplevel+--abbrev-ref HEAD(reuse the hardened git-exec resolver from the WT-354e branch), passes them intoHookHandler.Handle.- On register when
sessionIdnot found: if worktreePath+branch known AND exactly one existing session entry has that worktreePath+branch AND it is stale (LastHeartbeatUtcolder than ~5 min), rebind that entry'sKeyto the new sessionId and return it (preserves WT-id/ticket/desc). Else register fresh. UpdateLastHeartbeatUtcon every hook fire. Null worktreePath (non-git cwd) → no reclaim, degrade to today's sessionId keying. This is why it's collision-safe. - Tests: single-stale rebind preserves id; two-live no reclaim; null-path no reclaim; heartbeat refresh.
Consolidation prerequisite (do FIRST, council-gate the security merges)¶
Five states diverge; deployed exe (C:\Tools\worktree-identity\worktree-identity.exe, built
2026-07-11 12:46) is from wt/WT-75a4/p25-worktree-identity (only branch with the worktree verbs).
| Branch | tip | adds |
|---|---|---|
| master | 9339a33 | base + cross-worktree mail |
| council-fixes | 07031ec | TOCTOU / unbounded-stdin / git-missing hardening (SECURITY) |
| wt/WT-354e/wtid-council-deferred | 8796c81 | git-executable path-hijack hardening (SECURITY) |
| wt/WT-2505/polyharness-p25 | 60a7c24 | PreToolUse clobber guard (hook-pretool) |
| wt/WT-75a4/p25-worktree-identity | 0fae814 | worktree ownership: claim/release/list, hook-pretool, dead-pid lock |
Order: master ← council-fixes ← WT-354e (security, council-review both) ← WT-2505 ← WT-75a4
(resolve hook-pretool overlap between WT-2505 and WT-75a4). Rebuild ONE self-contained exe,
redeploy to C:\Tools\worktree-identity\ + fleet. THEN implement the design above on master.
Also confirm settings.json PreToolUse hook-pretool is satisfied by the redeployed exe (master
alone lacks that verb — the live hook only works because the deployed exe is from WT-75a4).