Skip to content

fix(mobile): preserve Markdown list width in chat bubbles - #2597

Merged
DoodleBears merged 3 commits into
mainfrom
codex/mobile-stream-layout-fix
Oct 22, 2026
Merged

DoodleBears merged 3 commits into
mainfrom
codex/mobile-stream-layout-fix

Conversation

@DoodleBears

@DoodleBears DoodleBears commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Issue #2596 | Agent claim

Why the change

Android Markdown lists can collapse to a single-character column inside content-sized chat bubbles, making long replies unreadable.

Special things to note

  • Merge risk: two-way door — revert this commit; small blast radius — supported Android Markdown list layout, including chat and Markdown previews, with no persistent data change. Review nested lists, short-content sizing and large text.
  • Verification: the real MessageBubble → Android Markdown renderer tree fails the new Yoga regression before the fix (14px long-list text, 0px nested text), then passes; 7 focused files / 64 tests, mobile typecheck, touched lint/format and bilingual changelog checks pass. Standalone Yoga 3.2.1 and synthetic glyph measurement do not qualify Android Fabric/shaping or FPS.
  • Default-font Android completed-list layout has matched native evidence; additional configuration failure and Human acceptance remain open. The prior 54.444–55.420s playback observation has not been remeasured; this PR changes no playback scheduling. Refs Android: long Markdown reply collapses to a narrow column and retains playback backlog #2596. Task: codex/local/01a16398-d657-75d0-9cfa-9a8a9f34b9c0.

Change outline

 MessageBubble (content-sized, maxWidth 80%)
   Android MarkdownView
     MarkdownText list row
       marker
-      body: flex: 1       // zero basis loses intrinsic width
+      body: flexShrink: 1 // content sizes the row, then wraps to fit

The problematic list style dates to 209fe8dcd1d8fe06bec2fe6542a68a2f246f510a (October 17), before the latest QA fixes; this does not establish the first affected native release.

The regression renders the actual components, carries their layout styles into Yoga, and checks completed/streaming 40-item Chinese lists, nested lists at three window widths with enlarged text, compact short lists and plain prose. Yoga is an exact-pinned development-only dependency.

Native comparison PARTIAL — 2026-10-22: tested base 914bfa57ed04807dc3f94a1ed6a4e678da898591 against runtime candidate b3c0f4236533226433b0e89102d707f25f955ca0 on the designated POCO 24069PC21G, Android 16/API 36, arm64, 1220 × 2712 pixels/density 480. The 4d77e61c successor only removed two test comments; the later integration head d8d677e4d1e3d889d006b746894b11395c8970c1 additionally merges main and was not run on the phone. These screenshots remain bound to the original base/candidate. Detailed evidence, build hashes, crops and limits.

Four previously committed synthetic Bot messages were reused through the real Host; canonical author/body hashes matched. Separate sequential Metro instances loaded the frozen base/candidate using the audited SDK 58 Debug APK, fingerprint 1d971f8f1e438ac99cb56339c9300cf53092be9f. No model, live stream or product instrumentation was used.

Default font 1.0 / dark Baseline → candidate Result
Short list, same first Text node 7 → 294 physical px; all three items visible after PASS
Nested list, same first Text node 7 → 666 px; nested content visible after PASS
40-item list One-character column → readable wrapping and item 40 ending Sampled layout PASS; automatic scroll positions differ
Plain long paragraph, same message Text node 846 → 846 px No observed width regression

Widths are native UI Automator Text-node bounds, not glyph-ink or full-height measurements. Long-list/prose screenshots differ in automatic scroll position, so they are not equal-offset pixel comparisons. The short/nested pairs use the same text and visible message position. Published crops remove status/notification and developer-overlay regions.

Additional failure / untested: after font 1.3/light-theme recreation, the long list remained wide, but Expo Router logged and displayed “Looks like you have configured linking in multiple places”; attribution is unresolved. Private app-only logs and the uncropped error screenshot are retained. This is not a clean font/theme matrix pass. OEM maximum, other widths, TalkBack, iOS, Human visual acceptance, live playback drain, history/Jump and FPS remain untested; the old 54.444–55.420s observation is not requalified by these completed messages.

Restoration complete: the earlier blocked attempt was recovered after the Human rebooted. The new comparison ended at 17:27:29.9775527Z: original Release APK was restored and pulled back with matching hash, eight settings/USB reverses match, own pairing/credential removed, own Host/Metro stopped and lease released. The Human's explicit Allow-notifications choice was preserved and read back. No uninstall or data clear.

Short list — default font, dark

All three fixed items are readable after; the bubble still fits short content.

Before

Before: Short list — default font, dark

After

After: Short list — default font, dark

Nested list — default font, dark

The same nested content is readable after instead of clipped into a narrow strip.

Before

Before: Nested list — default font, dark

After

After: Nested list — default font, dark

40-item list — default font, dark

Same canonical body and device settings; before shows the beginning, after the automatically selected end. This pair demonstrates the visible column-width change, not identical scroll geometry.

Before

Before: 40-item list — default font, dark

After

After: 40-item list — default font, dark

Plain-prose regression crops: before, after.

Integration d8d677e4d1e3d889d006b746894b11395c8970c1: ordinary merge of main a1656d18a70f1f115da41092ca159b59e8895f4f; the sole package conflict retains upstream @types/react-dom ~19.3.0 and this PR's development-only Yoga 3.2.1. The old Expo Doctor failure is preserved as historical evidence. Fresh frozen scripts-disabled installation, 7 focused files / 64 tests, mobile typecheck, touched format and changelog checks all pass; Expo Doctor now passes 20/20. Exact-head CI 39835907249 passed all applicable jobs, including three full test shards, mobile verification, Android module checks, static/build, docs and isolated Host smoke; real-model scenarios were skipped. Merged at 2026-10-22T19:06:06Z as bdcc996a1ae1fa6d83439647bda4e4643b2b21ae under the Human merge-first instruction. Native evidence above does not qualify this newer integrated main or streaming performance.

No HTML explainer is needed for this one-line styling change; the component outline and regression limits above describe the full behavior change.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue where Markdown lists in Android chat bubbles could collapse into a narrow column. List content now retains a more readable width in long replies and nested lists, including when text is enlarged or the screen size varies. This also applies while replies are streaming.

List flex:1 gives content a zero basis inside shrink-to-fit bubbles. Allow
shrinking without discarding intrinsic width, retaining compact short lists.
The renderer/Yoga regression failed with 14px long-list text before this fix.

Issue: #2596
Agent-Task: codex/local/01a16398-d657-75d0-9cfa-9a8a9f34b9c0
@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b8da7156-675a-4975-ab15-6be047c69bcb
📥 Commits

Reviewing files that changed from the base of the PR and between a1656d1 and d8d677e.

⛔ Files ignored due to path filters: 1
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing: 4
  • apps/mobile/package.json
  • apps/mobile/src/ui/markdown-text.tsx
  • apps/mobile/test/markdown-bubble-layout.test.tsx
  • changes/2596-markdown-list-width.md
+------------------------------------------------+
| I raised Series-B funding to review your code. |
+------------------------------------------------+
  \
   \     /)/)
        ( '')
        /  |
      o(___)
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Remove only the two explanatory comments from the Markdown layout regression. Verification limits remain in the PR and source report.

Issue: #2596

Agent-Task: codex/local/01a16398-d657-75d0-9cfa-9a8a9f34b9c0
@DoodleBears

Copy link
Copy Markdown
Contributor Author

Android native attempt — BLOCKED before matched layout comparison.

Frozen app inputs: base 914bfa57ed04807dc3f94a1ed6a4e678da898591, candidate b3c0f4236533226433b0e89102d707f25f955ca0. Independent diff audit confirms successor 4d77e61c69b4678d206412e05687b7b67506ebb0 removes only two test comments; the attempted app runtime remained b3c0.

  • Passed prerequisites: separate frozen installs, candidate Host/Client build, strict Android native fingerprint 1d971f8f1e438ac99cb56339c9300cf53092be9f, compatible audited arm64 Debug APK. Four fixed bodies entered a dedicated QA Host through the real direct channel_send tool; canonical Bot authors and exact body hashes matched. No model call was needed. Pairing fingerprints were verified in both directions.
  • Unexecuted: base/candidate message-width captures, short/nested/plain controls, font/theme matrix, streaming backlog, history/Jump and FPS. An Android notification permission prompt required Human input; later QA foreground checks refused capture. No native fix acceptance or after image is available.
  • Cleanup: own pairing removed, Host credential revoked, settings/reverse mappings matched, Host/Metro stopped and lease/heavy released at 2026-10-22T15:50:28Z. Original APK restoration remains pending: Android's installer stalled after both streamed and non-streamed uploads. Exact task-owned sessions were abandoned and clients stopped; current Debug app was force-stopped with data retained. Human reboot/reconnect was requested; recovery precedes another native test.

Source test results and CI remain separate from this blocked device attempt. This attempt does not establish that the previously observed playback backlog is fixed.

@DoodleBears

Copy link
Copy Markdown
Contributor Author

Android follow-up window windows-2596-layout-r2 completed, PARTIAL, resources released at 2026-10-22T17:27:29.9775527Z.

Exact base 914bfa57ed04807dc3f94a1ed6a4e678da898591 → runtime b3c0f4236533226433b0e89102d707f25f955ca0; POCO 24069PC21G / Android16 / 1220×2712 / density480. Compatible Debug APK SHA256 DB841DD80BEE8606B18150804CC0788A13761F87477D8138B0C47E745BDC7DC1, strict native fingerprint 1d971f8f1e438ac99cb56339c9300cf53092be9f. Comment-only successor 4d77e61c has unchanged runtime bytes, not a separately tested head.

Default font1.0/dark: short list same Text node 7→294px, nested 7→666px, both now fully readable; long list no longer one-character wide, candidate ending visible (automatic scroll positions differ); plain paragraph width 846px both. Same four canonical synthetic Bot messages and exact body hashes, no model/stream injection.

At font1.3/light, list width remained normal but Expo Router emitted duplicate linking configuration after activity recreation. Preserve this failure; no clean full-matrix, streaming/backlog/FPS/history/Jump/OEMmax/iOS or Human-acceptance claim. Existing Expo Doctor CI failure remains.

Recovery gap from the prior comment is resolved. Original Release SHA256 3B6A93CCA306A6AD854E9476C4D50E95DDD04CECDC8AF743D5605ED94779C848 was restored and pulled back; eight settings/reverses match; own pairing revoked/removed; processes/listeners/lease released. Human-selected notification Allow retained.

Immutable evidence and eight reviewed crops; screenshots are embedded in the PR body. Evidence commit af86f2c4c23341fbde843353914e67d6ffaa3daa is publication only.

@DoodleBears
DoodleBears marked this pull request as ready for review October 22, 2026 18:57
@DoodleBears
DoodleBears merged commit bdcc996 into main Oct 22, 2026
12 of 13 checks passed
@DoodleBears

Copy link
Copy Markdown
Contributor Author

Integration and merge complete: exact head d8d677e4d1e3d889d006b746894b11395c8970c1, ordinary main merge retaining upstream React DOM types 19.3 and Yoga 3.2.1; frozen install, 64 focused tests, mobile typecheck, touched format/changelog and Expo Doctor 20/20 passed locally. CI 39835907249 passed all applicable jobs (real-model scenarios skipped). Human-authorized normal merge completed at 2026-10-22T19:06:06Z: bdcc996a1ae1fa6d83439647bda4e4643b2b21ae.

Published Android PARTIAL evidence remains tied to base 914bfa57 / candidate b3c0f423, not this integration. Default-dark completed-list width improved; font/theme recreation linking error and remaining matrix are retained. Streaming backlog, hold/Jump and a 120 FPS target remain separate unverified work. Latest-main APK preparation is in progress; merge is not native qualification.

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