Skip to content

fix(android): keep link preview metadata UTF-16 safe#102988

Merged
steipete merged 2 commits into
openclaw:mainfrom
ly85206559:codex/android-link-preview-utf16-safe
Jul 9, 2026
Merged

fix(android): keep link preview metadata UTF-16 safe#102988
steipete merged 2 commits into
openclaw:mainfrom
ly85206559:codex/android-link-preview-utf16-safe

Conversation

@ly85206559

@ly85206559 ly85206559 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Android link previews cap Open Graph title and description metadata before rendering compact preview cards. Kotlin take(maxChars) counts UTF-16 code units, so it could leave an unpaired high surrogate when the cap landed between the two units of an emoji or another supplementary-plane character.

Why This Change Was Made

The final implementation keeps the existing 120/200-unit metadata limits while backing up one unit only when the boundary would retain a lone high surrogate. Review also moved that invariant into one Android-owned takeUtf16Safe helper shared with notification snapshot sanitation, replacing the earlier duplicate private implementation. This leaves production code net -1 LOC and one canonical truncation path.

User Impact

Long Android link-preview titles and descriptions no longer carry malformed UTF-16 at an emoji boundary. A split pair is omitted; a complete pair ending exactly at the cap remains intact. Notification snapshot truncation keeps its existing behavior through the shared helper.

Evidence

  • Exact reviewed head: 74386e4c7e566151934ca3debe6a82fd7e0bd9f9
  • Fresh autoreview: clean, 0 findings, overall confidence 0.86
  • git diff --check: pass
  • Exact-head GitHub CI run 29045458923: pass
    • android-test-play job 86212977276
    • android-test-third-party job 86212977364
    • android-build-play job 86212977286
    • android-ktlint job 86212977287
    • native-i18n job 86212977192
    • OpenGrep, security-fast, and preflight also passed
  • Required native prepare gate: pass at 2026-07-09T19:57:11Z, mode hosted_exact_or_recent_rebase, verified exact PR head/tree
  • Regression coverage verifies both split-pair removal and complete-pair preservation at the cap; existing notification surrogate coverage remains green

Known proof gap: no exact-head Android APK was available for device/emulator rendering. Source-blind runtime validation therefore reported 0 pass, 0 fail, and 4 blocked clauses; no device-render claim is made. Sanitized AWS fallback runs run_11199f6ce6ea and run_6565652416e0 were infrastructure-blocked before tests because the generic image lacked Java and then the Android SDK. The exact-head hosted Android matrix above is the runtime build/test proof.

Changelog is intentionally deferred: per contributor policy, this branch stays changelog-free; a maintainer-owned consolidated UTF-16 changelog follow-up will include #102988 and thank @ly85206559.

@openclaw-barnacle openclaw-barnacle Bot added app: android App: android size: XS triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. and removed triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. labels Jul 9, 2026
@ly85206559
ly85206559 force-pushed the codex/android-link-preview-utf16-safe branch from 2cf519c to d06a52f Compare July 9, 2026 16:19
@clawsweeper

clawsweeper Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 9, 2026, 3:57 PM ET / 19:57 UTC.

Summary
The PR adds a shared Android UTF-16-safe truncation helper, uses it for link-preview metadata and notification text caps, and adds a link-preview metadata boundary regression test.

PR surface: Other +14. Total +14 across 4 files.

Reproducibility: yes. source-level: current main caps sanitized og:title and og:description metadata with raw take(maxChars), so an emoji split at the limit can leave only the high surrogate. I did not run an Android app repro in this read-only review.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: vector/embedding metadata: apps/android/app/src/test/java/ai/openclaw/app/ui/chat/ChatLinkPreviewTest.kt. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🧂 unranked krab
Patch quality: 🦞 diamond lobster
Result: blocked until real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add redacted real Android behavior proof for a chat link preview whose title or description has an emoji at the truncation boundary, such as an app screenshot/video or runtime logs showing the rendered metadata is not left with a dangling surrogate.

Proof guidance:

  • [P1] Needs real behavior proof before merge: Missing: the PR body reports tests and local checks, but no after-fix real Android app screenshot/video, terminal live output, runtime logs, or linked artifact; contributors should post redacted proof and update the PR body to trigger re-review.

Risk before merge

  • [P1] The remaining blocker is evidentiary: the current head has focused unit-test and CI signal, but no redacted real Android chat-preview run, screenshot, recording, runtime log, or equivalent after-fix proof.

Maintainer options:

  1. Decide the mitigation before merge
    Land the narrow shared sanitizer after redacted real Android chat-preview proof shows emoji-at-boundary metadata renders without a dangling surrogate and required checks finish green.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P1] Human review should wait for redacted real Android behavior proof on the current head; no automated code repair is queued because no discrete patch defect was found.

Security
Cleared: Cleared: the diff only changes Android Kotlin string truncation and focused tests; no secrets, dependency, workflow, package, or supply-chain surface changed.

Review details

Best possible solution:

Land the narrow shared sanitizer after redacted real Android chat-preview proof shows emoji-at-boundary metadata renders without a dangling surrogate and required checks finish green.

Do we have a high-confidence way to reproduce the issue?

Yes, source-level: current main caps sanitized og:title and og:description metadata with raw take(maxChars), so an emoji split at the limit can leave only the high surrogate. I did not run an Android app repro in this read-only review.

Is this the best way to solve the issue?

Yes. The PR fixes the sanitizer boundary used by both title and description metadata and shares the already-tested Android notification truncation rule instead of adding a second policy path.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against ee9d9ea6dbb7.

Label changes

Label justifications:

  • P2: This is a focused Android chat-preview correctness fix with limited blast radius and no evidence of data loss, security bypass, crash loop, or broken core runtime.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🧂 unranked krab and patch quality is 🦞 diamond lobster.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: Missing: the PR body reports tests and local checks, but no after-fix real Android app screenshot/video, terminal live output, runtime logs, or linked artifact; contributors should post redacted proof and update the PR body to trigger re-review.
Evidence reviewed

PR surface:

Other +14. Total +14 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 0 0 0 0
Tests 0 0 0 0
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 4 26 12 +14
Total 4 26 12 +14

What I checked:

Likely related people:

  • steipete: GitHub PR/path history shows steipete authored the Android link-preview introduction, image/cache follow-ups, and the shared-helper refactor commit on this PR; the live PR is also assigned to steipete. (role: introduced behavior and recent area contributor; confidence: high; commits: 989df7362532, a959d5600f8a, 74386e4c7e56; files: apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatLinkPreview.kt, apps/android/app/src/test/java/ai/openclaw/app/ui/chat/ChatLinkPreviewTest.kt, apps/android/app/src/main/java/ai/openclaw/app/Utf16Text.kt)
  • ly85206559: ly85206559 authored the merged Android notification UTF-16 boundary fix that introduced the sanitizer rule this PR now shares with link-preview metadata. (role: sibling invariant contributor; confidence: high; commits: 50ec0312063e, 3e787f318785, 354b2d5b0363; files: apps/android/app/src/main/java/ai/openclaw/app/node/DeviceNotificationListenerService.kt, apps/android/app/src/test/java/ai/openclaw/app/node/NotificationsHandlerTest.kt, apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatLinkPreview.kt)
  • NianJiuZst: NianJiuZst authored the recent merged Android link-preview cancellation fix touching the same fetcher and test files, so they are useful adjacent context even though the metadata truncation policy is separate. (role: recent adjacent contributor; confidence: medium; commits: 50cbcd887a22, 67be0cda4460; files: apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatLinkPreview.kt, apps/android/app/src/test/java/ai/openclaw/app/ui/chat/ChatLinkPreviewTest.kt)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (2 earlier review cycles)
  • reviewed 2026-07-09T16:41:11.431Z sha c83f93f :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-09T19:50:27.356Z sha 74386e4 :: needs real behavior proof before merge. :: none

@ly85206559
ly85206559 force-pushed the codex/android-link-preview-utf16-safe branch 2 times, most recently from 1eea530 to c83f93f Compare July 9, 2026 16:29
@ly85206559
ly85206559 marked this pull request as ready for review July 9, 2026 16:32
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jul 9, 2026
@steipete steipete self-assigned this Jul 9, 2026
@steipete
steipete force-pushed the codex/android-link-preview-utf16-safe branch from c83f93f to 74386e4 Compare July 9, 2026 19:45
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Land-ready review completed at exact head 74386e4c7e566151934ca3debe6a82fd7e0bd9f9.

What changed during review:

  • Moved UTF-16-safe capping into one Android-owned helper shared by link-preview metadata and notification snapshots.
  • Preserved the existing UTF-16 code-unit limits; only a high surrogate split at the boundary is omitted.
  • Strengthened coverage to distinguish a split pair from a complete pair ending exactly at the cap.
  • Final diff: 4 files, +26/-12; production code is net -1 LOC.
  • Fresh autoreview: clean, 0 findings, overall confidence 0.86.

Proof:

  • git diff --check — pass.
  • Exact-head CI run 29045458923 — pass.
    • Android test Play: job 86212977276
    • Android test third-party: job 86212977364
    • Android build/lint Play + third-party: job 86212977286
    • Android ktlint: job 86212977287
    • Native i18n: job 86212977192
    • OpenGrep, security-fast, and preflight also passed.
  • scripts/pr review-init 102988
  • scripts/pr review-artifacts-init 102988
  • scripts/pr review-validate-artifacts 102988 — READY FOR /prepare-pr, 0 findings.
  • OPENCLAW_TESTBOX=1 scripts/pr prepare-run 102988 — hosted exact/recent-rebase gate passed at 2026-07-09T19:57:11Z; remote head/tree verified.

Known proof gaps:

  • No device/emulator rendering claim. CI published no exact-head APK; the connected emulator has an older build. Source-blind runtime validation was 0 pass, 0 fail, 4 blocked.
  • Sanitized AWS fallback runs run_11199f6ce6ea and run_6565652416e0 were infrastructure-blocked before test execution because the generic image lacked Java and then an Android SDK.
  • Changelog is intentionally deferred to the maintainer-owned consolidated UTF-16 follow-up; this contributor branch remains changelog-free and the follow-up will thank @ly85206559.

No blocking or optional review findings remain. Thanks @ly85206559.

@steipete
steipete merged commit 1d4c170 into openclaw:main Jul 9, 2026
50 checks passed
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 10, 2026
* fix(android): keep link preview metadata UTF-16 safe

* refactor(android): share UTF-16-safe truncation

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: android App: android P2 Normal backlog priority with limited blast radius. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants