ingest: stop routing plain .md/.txt through MIME extraction (fixes #1)#2
Open
owrede wants to merge 1 commit into
Open
ingest: stop routing plain .md/.txt through MIME extraction (fixes #1)#2owrede wants to merge 1 commit into
owrede wants to merge 1 commit into
Conversation
…ntextFit#1) _preprocess_file sent every discovered file through _extract_email_text. For anything that is not a markdown-exported email, that takes the raw MIME path: compat32 get_payload(decode=True) on a str payload round-trips the text through raw-unicode-escape + utf-8/ignore, silently deleting all chars in U+0080..U+00FF (umlauts, ß, accents) and turning chars above U+00FF into literal \uXXXX sequences. A German-language vault loses every umlaut in the index ('Köln' -> 'Kln'). Gate MIME extraction behind _looks_like_email(): only .eml files, markdown-exported emails (# Email: / **From:**), or files opening with RFC-5322 headers are parsed as email; everything else is ingested verbatim. Also read files as explicit UTF-8 instead of the locale default. Regression test ingests a .md with umlauts/CJK/emoji end-to-end and asserts the decoded token stream still contains them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Fixes #1.
Root cause
_preprocess_fileroutes every discovered file through_extract_email_text. Anything that isn't a markdown-exported email falls into the raw-MIME branch, where compat32get_payload(decode=True)on a str payload re-encodes viaraw-unicode-escapeand then decodes withutf-8, errors="ignore". Net effect on plain text:Köln→Kln,Straße→Strae\uXXXXsequence in the indexed textFor any non-English corpus this silently corrupts the entire index — the source files are untouched, so it's easy to miss.
Fix
_looks_like_email(path, raw)helper: only.emlfiles, markdown-exported emails (# Email:/**From:**), or files opening with RFC-5322 headers go through_extract_email_text; everything else is ingested verbatim.read_text(encoding="utf-8", errors="ignore")) instead of the locale default.Downstream behavior is unchanged:
is_emailstill derives fromemail_metakeys, and the non-email branch returns{"source": str(path)}— truthy, same as_extract_email_text's fallback, soemail_meta or auto_extractor.extract(...)resolves identically.Tests
tests/test_ingest_unicode.py: gating unit tests + an end-to-end regression test that runs_preprocess_fileon a.mdcontaining umlauts/CJK/emoji and asserts the decoded token stream still contains them.tests/test_email_calendar_ingestion.pypass.Suggested follow-up (not in this PR)
The gate removes the trigger, but the lossy round-trip inside
_extract_email_textremains reachable for real 8bit-encoded.emlfiles. Root fix: parse real emails from bytes —email.message_from_bytes(raw.encode("utf-8"), policy=email.policy.default)— soget_payload(decode=True)returns properly CTE-decoded bytes. Happy to send that as a second PR if wanted.🤖 Generated with Claude Code