Skip to content

fix(core): report case-only Wiki scope collisions instead of failing the run - #1789

Open
phernandez wants to merge 1 commit into
mainfrom
wiki-projection-case-collision
Open

phernandez wants to merge 1 commit into
mainfrom
wiki-projection-case-collision

Conversation

@phernandez

Copy link
Copy Markdown
Member

Fixes #1787

Problem

plan_wiki_projection raised ValueError: Wiki projected scopes must be unique when compared as portable paths when two source folders differed only by letter case or Unicode normalization, for example marketing/Teams and marketing/teams. The planner is pure and runs over the whole project, so one collision failed the entire run. Every later run hit the same folders and failed the same way. That project's Wiki stopped updating, and nothing told the user why. Production has had 69 failures since 10-11 (cloud Logfire issue #2636). It recurs daily on one workspace and happened earlier on another (customers/CPC against customers/cpc).

The check that raised existed at three sites: the queued scopes, the scopes derived from notes, and the ancestors of retained projector-owned indexes. This change covers all three.

Design

The portable-path uniqueness rule stays. Two spellings of one folder would write their index.md and log.md to the same file on a case-insensitive sync target. What changes is the outcome when the rule is broken.

  • _scope_collisions groups every candidate scope by its portable path key. These are note folders, queued or requested scopes, and retained index ancestors. Any key with more than one spelling becomes a WikiScopeCollision.
  • Every spelling in a collision is left out of the plan. No index or log is written for it, and parent indexes don't link to it, because there is no index to link to.
  • Every other scope still projects, and the output watermark advances as normal.
  • The collision is returned as a closed, typed value on the result: WikiProjectionResult.scope_collisions. Its user-facing text also goes into result.warnings. That is the existing per-run diagnostic channel. bm wiki prints warnings for each project, and Cloud already copies result.warnings into the run ledger details that the Wiki state API returns. The user sees which folders to rename without any new plumbing.
  • The state stays current. A new state would break Cloud's exhaustive status match. partial means waiting for materialization and is retried, which would loop on something only a rename can fix.

Folder collisions with a source note path (a folder spelled like an existing .md note) still raise, as before. That is a different invariant and out of scope here.

I rejected the alternative, projecting each spelling into a scope with a stable suffix. A Wiki index.md lives in the folder it indexes. A suffixed scope would either put the index in a folder that doesn't hold the notes, or invent folders the user never created. Then those folders would need their own lifecycle when the user later renames one. Skipping and reporting keeps the output honest and gives the user one clear action.

Tests

  • New: test_case_only_folder_collision_does_not_fail_the_rebuild. A manual rebuild with marketing/Teams and marketing/teams completes. Root, guides, guides/deep and marketing all project. marketing/index.md still lists its own notes and doesn't link to either colliding folder. The collision is on scope_collisions and in warnings, the state is current, and the watermark advances.
  • New: test_case_only_folder_collision_does_not_fail_an_incremental_run. Same shape for an accepted edit inside one of the colliding folders, which is the production path.
  • These tests pinned the old raise and now assert that the collision is reported and skipped:
    • test_projection_skips_nonportable_duplicate_scopes, covering Foo/foo and NFC/NFD café;
    • the three incremental retained-index collision tests (..._skips_case_folded_existing_empty_scope, ..._skips_existing_scope_colliding_with_unchanged_notes, ..._skips_retained_scope_ancestor_collisions).
  • These are unchanged and still pass:
    • truly identical paths still fail at the snapshot (duplicate source note paths, and case-folded and Unicode-normalized duplicate reserved documents);
    • scope against source note path collisions still raise.

Load-bearing check:

  • With the old raise put back on collisions (types kept, so the module imports), all 7 collision tests fail. With the fix restored, all 105 projector tests pass.
  • With the parent-index link filter removed, the same 7 fail, so the filter is load-bearing too.

Commands: just fast-check passes, and tests/indexing/test_wiki_projector.py passes (105). OPENAI_API_KEY= just fast-test (testmon) had 225 passed and 1 failed. The failure is test_benchmark_search_query_latency_by_mode, which fails the same way on unmodified main.

Follow-up (Cloud, not in this PR)

Cloud stores warnings today, so this is visible through the Wiki state API right away. The web UI could render scope_collisions as a "rename one of these folders" prompt.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KjsDUcHANBa17M84sKxFG3

…the run

Two folders that differ only by case or Unicode normalization (for
example marketing/Teams and marketing/teams) made plan_wiki_projection
raise. The planner covers the whole project, so every later run failed
the same way and the project's Wiki stopped updating with no message.

Keep the portable-path uniqueness rule, but leave every colliding
spelling out of the plan and return it as a typed WikiScopeCollision on
WikiProjectionResult.scope_collisions, with its text in warnings (the
channel bm wiki and the Cloud run ledger already surface). All other
scopes project and the watermark advances. Parent indexes no longer
link to a skipped folder.

Fixes #1787

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KjsDUcHANBa17M84sKxFG3
Signed-off-by: phernandez <paul@basicmachines.co>
@phernandez phernandez added the cost-review-2026-10 October 2026 COGS review: cost leaks, heavy tenants, and production error triage label Oct 20, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-20T04:10:55.322095Z 63c7331 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cost-review-2026-10 October 2026 COGS review: cost leaks, heavy tenants, and production error triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wiki projection fails the whole run when folders differ only by case

1 participant