Summary
Two unrelated repositories whose paths end in the same segment derive one slug, and publishing the second appends its spec to the first one's version history.
Reproduction
- Publish an analysis of
https://github.com/openai/whisper without passing slug. deriveSlug returns whisper, and the entry is written as v1.
- Publish an analysis of a different repo,
https://github.com/acme/whisper, again without slug. It derives whisper too.
- Read
entries/<ns>/whisper/ and index.yaml.
Expected behavior
The second publish should not land inside the first project's entry. docs/library-format.md says slugs come "with collision-handling via a trailing -2, -3, etc.", which would have given whisper-2.
Actual behavior
The second spec is written as v2 of the existing entry. The entry's version history now spans two unrelated codebases. Because buildIndexEntry reads only the newest version's metadata, index.yaml reports the second repo's source_repo for the entry as a whole, so the listing attributes every version to whichever repo published last. Nothing warns at publish time or afterwards.
The documented -2 suffixing does not exist. deriveSlug in core/library.ts is a pure string function with no library access, so it cannot detect a collision, and publishEntry never compares source_repo either.
There is a quieter variant: if the two specs happen to have identical bytes, the content-hash branch takes the metadata-only path and overwrites the first project's source_repo and headline in place without even creating a version.
Environment
- Surface: both. On MCP,
slug is optional and falls back to derivation (mcp-server/server.ts, args.slug ?? deriveSlug(sourceRepo)). On Pi, slug and source_repo both come from ctx.cwd, so two same-named directories under different parents collide.
- CodeCartographer version: 0.16.0 (
77262ad)
Additional context
Found while auditing docs/library-format.md against core/library.ts. Related doc drift is filed separately.
Summary
Two unrelated repositories whose paths end in the same segment derive one slug, and publishing the second appends its spec to the first one's version history.
Reproduction
https://github.com/openai/whisperwithout passingslug.deriveSlugreturnswhisper, and the entry is written asv1.https://github.com/acme/whisper, again withoutslug. It deriveswhispertoo.entries/<ns>/whisper/andindex.yaml.Expected behavior
The second publish should not land inside the first project's entry.
docs/library-format.mdsays slugs come "with collision-handling via a trailing-2,-3, etc.", which would have givenwhisper-2.Actual behavior
The second spec is written as
v2of the existing entry. The entry's version history now spans two unrelated codebases. BecausebuildIndexEntryreads only the newest version's metadata,index.yamlreports the second repo'ssource_repofor the entry as a whole, so the listing attributes every version to whichever repo published last. Nothing warns at publish time or afterwards.The documented
-2suffixing does not exist.deriveSlugincore/library.tsis a pure string function with no library access, so it cannot detect a collision, andpublishEntrynever comparessource_repoeither.There is a quieter variant: if the two specs happen to have identical bytes, the content-hash branch takes the metadata-only path and overwrites the first project's
source_repoandheadlinein place without even creating a version.Environment
slugis optional and falls back to derivation (mcp-server/server.ts,args.slug ?? deriveSlug(sourceRepo)). On Pi,slugandsource_repoboth come fromctx.cwd, so two same-named directories under different parents collide.77262ad)Additional context
Found while auditing
docs/library-format.mdagainstcore/library.ts. Related doc drift is filed separately.