feat(learner): collapse cross-OS duplicate projects in the registry#22
Open
Sergio-LPA wants to merge 1 commit into
Open
feat(learner): collapse cross-OS duplicate projects in the registry#22Sergio-LPA wants to merge 1 commit into
Sergio-LPA wants to merge 1 commit into
Conversation
The per-project id is sha256(remote || root). A project with no git remote
therefore gets a DIFFERENT id on each OS (its root differs: /Users/me/Proj
vs C:/Users/Me/Proj), so with a shared registry (e.g. a synced folder) the
same project appears twice — duplicated in /projects, /eod and cross-project
instinct search.
Match on a cross-OS-stable key instead: the git remote when present, else
the project name. The two sightings collapse into one entry — each per-OS id
kept in aliases[], each observed root under roots.{posix,windows}. Projects
with a remote already shared one id and are unaffected; the remote key beats
the name so two distinct same-named projects never merge.
Purely additive: aliases, roots and crossKey are optional fields ignored by
readers that don't use them.
New tests/test-crossos-registry.sh (5 hermetic tests). Existing suites pass:
test-install-upgrade 21/21, test-registry-isolation 4/4, test-eod-gather 8/8.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Luispitik
requested changes
Jun 10, 2026
Luispitik
left a comment
Owner
There was a problem hiding this comment.
The diagnosis is right and in scope: project ids are sha256(remote || root), so a no-remote project gets a different id per OS and duplicates in synced registries. The diff applies clean on v4.6.1 and the new code is safe (no eval, execFileSync with args). But I reproduced three functional problems by running the patched hook, so this needs another iteration:
- Same-machine false merge (regression, data loss). Two different no-remote projects that share a folder name on the same machine (think
clientA/scriptsandclientB/scripts) collapse silently into one entry, and one root disappears from the registry (roots.windowsoverwritten — same os-family). Reproduced with the real hook./eodresolves roots by name, so it would attribute git commits to the wrong project. Fix: only collapse by name when the os-family actually differs, e.g.registry.projects.find(p => p && p.crossKey === crossKey && p.root && projectRoot && osFamily(p.root) !== osFamily(projectRoot))
- Pre-existing duplicates never merge. The lookup matches by id first, so a registry that already contains both entries (the synced-via-Nextcloud scenario that motivates this PR) keeps both forever — each machine just updates its own entry. Reproduced. Add a post-upsert migration pass that merges entries with identical
crossKey(union of aliases/roots, oldestcreated, newestlast_seen) — or hook it into_dream.shhygiene. As written, the PR only prevents future duplicates from a clean registry; it doesn't cure the reported symptom. - The new test fails on Windows Git Bash (suite exit 1; 1 of the 5 cases): MSYS converts the posix fixture path
/Users/tester/CrossProjpassed as argv intoC:/Program Files/Git/Users/..., soroots.posixnever registers. ExportMSYS_NO_PATHCONV=1/MSYS2_ARG_CONV_EXCL='*'at the top of the test, or pass fixture paths via env vars instead of argv. Also drop the|| r.projects[0].id==='bbbbbbbbbbbb'clause in test 3 — as written it passes even when the posix run was never processed, which is exactly what happens on Git Bash today.
Please also:
- Add an anti-regression test: two same-name no-remote projects with different roots in the same os-family must stay 2 entries.
- Teach the consumers about
aliases:commands/projects.md(step 3) should also count observations fromhomunculus/projects/{alias}/;_eod-gather.shshould register aliases in itsregistry[]map (for (const a of p.aliases||[]) registry[a] = {name:p.name, root:p.root}). - Document the known asymmetry in a code comment: if remote detection fails on one machine (git not on PATH for
execFileSync), that sighting falls back to aname:crossKey and won't match theremote:entry — duplicate persists.
Good direction — with the cross-OS restriction and the migration pass this becomes a clean merge. Windows Git Bash compatibility is non-negotiable in this repo (it's where most users hit bugs).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The per-project id is
sha256(remote || root). For a project with no git remote, the id is derived from the root — which differs per OS:/Users/me/ProjC:/Users/Me/ProjSo the same project gets a different id on each machine. When the registry (
_sinapsis-projects.json) is shared across machines — e.g. a Nextcloud/Dropbox/iCloud-synced~/.claude— that one project shows up as two entries, duplicating it in/projects,/eod, and cross-project instinct search.Projects with a remote are unaffected (the remote is identical across machines, so the id already matches).
Fix
Match on a cross-OS-stable key instead of the raw id: the git remote when present, otherwise the project name. The two sightings then collapse into a single entry:
aliases[](so future sessions resolve without a re-scan)roots.{posix,windows}The change is purely additive —
aliases,rootsandcrossKeyare new optional fields; existing readers that don't use them are unaffected. Behaviour for remote-backed projects is unchanged.Tests
New
tests/test-crossos-registry.sh— 5 hermetic tests driving the real hook via a sandboxHOME:roots.posixandroots.windowsrecordedExisting suites re-run clean:
test-install-upgrade21/21test-registry-isolation4/4test-eod-gather8/8Notes
~/.claudevia Nextcloud, where non-git folders (the same logical project) appeared twice in/eod. Follow-on to the v4.5.1 cross-OS/eodwork.