Skip to content

fix(migrate): under() panics when a trigger length splits a multi-byte char - #166

Open
charlesdove977 wants to merge 1 commit into
ChristopherKahler:mainfrom
charlesdove977:fix/under-char-boundary-panic
Open

charlesdove977 wants to merge 1 commit into
ChristopherKahler:mainfrom
charlesdove977:fix/under-char-boundary-panic

Conversation

@charlesdove977

Copy link
Copy Markdown

@ChristopherKahler heads up, this one takes down the SessionStart hook for any workspace that has a markdown file with a multi-byte char in its path.

Bug

base hook session-start panics on 0.15.1 and 0.15.2 (and current main):

thread 'base-main' panicked at src/migrate.rs:704:15:
end byte index 49 is not a char boundary; it is inside '→' (bytes 48..51 of string)

under() byte-slices rel[..dir.len()]. When a path like graphify-out/obsidian/Auto-reply → engagement → algorithm boost.md (graphify's Obsidian export names notes this way) has a multi-byte char straddling the byte offset equal to a trigger's length, the slice panics and the whole hook exits 101. Claude Code shows it as SessionStart:startup hook error every session.

Fix

rel.get(..dir.len()).is_some_and(|head| head.eq_ignore_ascii_case(dir)). get returns None off a char boundary; a split char means the prefix can't match anyway, so it's a miss instead of a crash. Behavior on every valid boundary is unchanged.

Verification

  • New assert !under("notes/a → b.md", "notes/a x") in under_is_a_path_test_not_a_string_prefix: panics at migrate.rs:704 without the fix, passes with it.
  • Release build of this branch runs base hook session-start in the affected workspace with exit 0.
  • cargo test: 556 pass. graph::tests::purge_apply_deletes_unread_spares_recent_and_snapshots and purge_dry_run_selects_by_recency_and_writes_nothing fail identically on unmodified main locally, so they're unrelated to this change.

🤖 Generated with Claude Code

…te char

under() byte-sliced rel[..dir.len()]. When a markdown path holds a
multi-byte char (e.g. an Obsidian note named "a → b.md") at the byte
offset equal to a trigger's length, the slice is not a char boundary
and the whole process panics. That panic surfaces as a SessionStart
hook error on every session in any workspace holding such a file.

Use str::get, which returns None off a char boundary: a split char
means the prefix cannot match anyway, so it is a miss, not a crash.
Adds a regression assert that panicked at migrate.rs:704 before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant