feat(shared): bare-mention scanner, code-fence normalizer, structural plain text (#193) - #254
Conversation
…tural plain text (#193) Ports upstream 5c926f19 (#604), the core half of 764e4759 (#817), and the shared halves of d4c52cad (#652), e71bfead (#843) and 683eadc1 (#947): - chat_sdk.shared.mentions: replace_bare_mentions / mask_code_spans / MentionReplacer (char-for-char port of adapter-shared mentions.ts) - chat_sdk.shared.code_fences: normalize_code_fences - ast_to_plain_text keeps structural whitespace (blank line between paragraphs, newline-separated list items/blockquote children, tab-separated table cells, empty table rows dropped) Utilities only; adapters adopt them in #206/#209/#229/#239. Closes #193 Part of #184
|
Warning Review limit reachedNext included review available in 42 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (15)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ence edge cases, exact fidelity names (#193)
# Conflicts: # CHANGELOG.md # scripts/fidelity_target.json
|
Merge gate: CI green (Lint & Type Check, test (3.12), test (3.13), Analyze (actions), Analyze (python), CodeQL) on 7499a6e (d0140cf + clean merge of origin/main: #202 cards/modals, #240 state-pg, #252 github; only CHANGELOG and the generated fidelity_target.json conflicted, the latter regenerated: missing 273 -> 256); local Codex review (gpt-6-astra, xhigh, --base origin/main) on d0140cf: "No actionable defects found. The changes match the targeted upstream implementations"; 2 astra rounds (no re-review after the merge: no src/tests conflicts and no overlapping modules with the newly merged PRs; full local validation green, 5759 passed, strict 733/733, pyrefly 0 errors); CodeRabbit rate-limited, no other bot findings. Merging with --admin (Protect Main requires a code-owner approval). |
Summary
Ports upstream's shared text utilities into
chat_sdk/sharedand bringsast_to_plain_textin line with upstreamtoPlainText. The new functions are utilities only; no adapter uses them yet.chat_sdk.shared.mentions: a character-for-character port ofadapter-shared/src/mentions.ts. It providesreplace_bare_mentions(text, replacer),mask_code_spans(text, replacement=" ")andMentionReplacer. The scanner skips inline and fenced code,http(s)://URLs (any case), schemelesshost.tld/…paths, emails and<…>tokens.chat_sdk.shared.code_fences: a port ofcode-fences.ts, providingnormalize_code_fences(text, *, convert_text=None, convert_code=None).MentionReplacerare exported fromchat_sdk.shared.ast_to_plain_textis rewritten as a single recursive_plain_text_node. It walks children with an explicit loop, which keeps one Python frame per nesting level, so deep blockquotes/lists do not overflow the stack beforeparse_markdownwould:\n\n;list,listItemandblockquotechildren are joined with\n;tableRowcells are joined with\t, keeping empty cells;tablerows are joined with\n, dropping rows that are empty after JStrim();value/altis returned as-is.shared/_js_compat.pyholds the JStrim()whitespace set (JS_WHITESPACE). The scanner's boundary test,trimStartand the table-row check all use it.Upstream commits mapped
d4c52cad(#652)replaceBareMentions→replace_bare_mentions5c926f19(#604)toPlainTextstructural whitespace764e4759(#817)markdown.tshalf only (table cells/rows). The Slack half is #210e71bfead(#843)normalizeCodeFences. Adoption is #209/#239683eadc1(#947)maskCodeSpans. Slack adoption is #209Tests ported
markdown.test.ts→tests/test_markdown_faithful.py: all 8 named tests. The 6toPlainTexttests assert exact values; the 2markdownToPlainTexttests use upstream's regex.chat.test.ts→tests/test_chat_faithful.py: "should call onNewMention for newline-separated GitHub bot mentions" and "should not call onNewMention for concatenated GitHub bot mention text".thread.test.ts: "should preserve double newlines (paragraph breaks) in streamed text" now expects"hello.\n\nhow are you?".adapter-shared/src/mentions.test.ts→ newtests/test_shared_mentions.py: all 17replaceBareMentionscases and all 6maskCodeSpanscases.adapter-shared/src/code-fences.test.ts→ newtests/test_shared_code_fences.py: all 11 cases.tests/test_github_webhook.py.tests/test_github_format.py.@aat index 0, a trailing@, a lone backtick, an empty string, an unclosed<at end of string;é@x→é<@x>);HTTPS://host/@xand other mixed-case schemes are left untouched;trimStartand the table-row check;$vs\Z, and\dvs[0-9](an Arabic-Indic digit is not an ordered-list marker);table_to_asciioutput is unchanged.RecursionError;<...>tokens that contain an@(<!subteam^S1|@team>);close >= endin the mention code scanner. All values were checked against the chat@4.41.1 TS under Node.Differential check (not committed): I ran the upstream TS sources at
chat@4.41.1directly under Node against the Python ports.mentions.tsandcode-fences.ts: about 130k random inputs, built from the delimiter alphabet plus JS/Python whitespace edge characters. 0 mismatches.plainTextNode, run on 20k Python-parsed ASTs: 0 mismatches.Fidelity
Delta vs committed report (HEAD): missing 282 -> 273 (-9).markdown.test.tsgoes 7 → 0 andchat.test.tsgoes 33 → 31. Strict at the pin is still 733/733.Divergences
None in behavior. JS string semantics (ASCII classes, the
trim()whitespace set, case-insensitivestartsWith,undefinedfor out-of-range indexes,$,\d) are reproduced explicitly and documented indocs/UPSTREAM_SYNC.md("Shared text utilities"). That section also adds the two module-mapping rows.Two test-level notes:
toContain. The port asserts the exact TS output,"` <@U1> help"."@test-bot\n\nhi there"instead of upstream's single newline. The Python parser always kept soft breaks, so a paragraph break actually exercises #604 on that code path.Consumer impact (high)
message.text/extract_plain_textoutput changes wherever the base extractor runs:\n);This affects:
fetch_messages/parse_message;text, and the plain-text fallback bodies);thread.post(...)results (SentMessage.text).Not affected: Slack and Google Chat (both override
extract_plain_text) and Discord live-gateway text (rawcontent). Slack text changes later, in #209/#210. Teams must not adopt the mention scanner (#216).Closes #193
Part of #184
Merge gate
Review findings (2 independent reviewers, 5 findings): 5 fixed, 0 declined.
_plain_text_node->_child_plain_text). It hitRecursionErrorat about half the depthparse_markdownaccepts:'>' * 600 + ' x'crashed, while main returned'x'. Fixed: the child walk is now an explicit loop inside_plain_text_node. The regression teststest_deeply_nested_blockquote_does_not_overflow_the_stackandtest_deeply_nested_list_does_not_overflow_the_stackfail on the previous HEAD and pass now.<...>skip inmentions.py. Fixed:TestReplaceBareMentionsClosedAngleTokenskills the "drop the angles branch" mutant.newlineseparated/paragraphseparated, so they are now exact matches.scripts/fidelity_target.jsonwas stale. Fixed: regenerated on the final HEAD. Missing is unchanged at 273; the PR-level delta vs main is stillmissing 282 -> 273 (-9).gpt-6-astra: 1 round, on
d0140cf. Verdict: No actionable defects found.Bots: CodeRabbit skipped the draft and was then rate-limited, so it left no inline review comments. No gemini comments.
CI (on
d0140cf): all green. That covers Tests 3.12/3.13, CodeQL, and Lint & Type Check (ruff, audit, pin drift, strict fidelity, pyrefly).Local validation: all green. ruff check/format; test-quality audit (0 hard failures);
--check-docs; strict fidelity 733/733; pytest 5672 passed / 13 skipped; pyrefly 0 errors.