feat(android): og:image thumbnails on link preview cards#101396
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed July 7, 2026, 2:03 AM ET / 06:03 UTC. Summary PR surface: Other +288. Total +288 across 4 files. Reproducibility: not applicable. this is a feature PR, not a bug report with a failing current-main reproduction path. Source inspection confirms current main is text-only and the PR adds the requested Android thumbnail path. Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review detailsBest possible solution: Keep the Android thumbnail implementation narrow and user-initiated, land it only after redacted device/emulator proof and maintainer acceptance of the remote-image boundary, and leave current text-only previews as the fallback when image fetch or decode fails. Do we have a high-confidence way to reproduce the issue? Not applicable: this is a feature PR, not a bug report with a failing current-main reproduction path. Source inspection confirms current main is text-only and the PR adds the requested Android thumbnail path. Is this the best way to solve the issue? Yes directionally: Android chat UI is the right owner boundary and the patch reuses the existing locked-down preview fetcher. It is not merge-ready until real Android visual proof and security-boundary review are complete. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against b66220948882. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Other +288. Total +288 across 4 files. View PR surface stats
Security concerns:
What I checked:
Likely related people:
What the crustacean ranks mean
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
|
|
Merged via squash.
|
…plicit intents (#101799) * fix(android): keep cold-start gateway auto-connect from overriding explicit intents NodeRuntime's init-time auto-connect now atomically claims the first gateway lifecycle intent (CAS 0->1) and stands down permanently when any explicit connect/disconnect/switch intent already exists, so a late discovery emission can no longer override a user decision. This was also the root cause of the CI-only flakes in GatewayBootstrapAuthTest (refreshGatewayConnection_* at :616/:627 and switchToUndiscoveredGateway* on PRs #101002/#101387/#101396). GatewaySession.Connection.sendRequestFrame now starts its response watcher with CoroutineStart.ATOMIC: disconnect teardown cancels connectionJob right after failPending(), and a DEFAULT-start watcher still queued for dispatch was cancelled without running, silently dropping the terminal UNAVAILABLE onError owed to fire-and-forget callers (root cause of the flaky GatewaySessionInvokeTest.disconnectReportsUnknownOutcomeForFireAndForgetRpc). Tests neutralize runtime background work (cancel+join the runtime scope) before arming the registry and scripting lifecycle steps, and add regression coverage for the auto-connect intent claim. Proof: refresh flake reproduced at iteration 1 under taskset -c 0,1 on a Blacksmith Linux box; post-fix 3 pinned stress rounds (120/150 looped iterations) plus full :app:testPlayDebugUnitTest (109 classes, 0 failures) and :app:ktlintCheck green on the same box. * chore(i18n): resync native inventory line positions after NodeRuntime edits
…plicit intents (openclaw#101799) * fix(android): keep cold-start gateway auto-connect from overriding explicit intents NodeRuntime's init-time auto-connect now atomically claims the first gateway lifecycle intent (CAS 0->1) and stands down permanently when any explicit connect/disconnect/switch intent already exists, so a late discovery emission can no longer override a user decision. This was also the root cause of the CI-only flakes in GatewayBootstrapAuthTest (refreshGatewayConnection_* at :616/:627 and switchToUndiscoveredGateway* on PRs openclaw#101002/openclaw#101387/openclaw#101396). GatewaySession.Connection.sendRequestFrame now starts its response watcher with CoroutineStart.ATOMIC: disconnect teardown cancels connectionJob right after failPending(), and a DEFAULT-start watcher still queued for dispatch was cancelled without running, silently dropping the terminal UNAVAILABLE onError owed to fire-and-forget callers (root cause of the flaky GatewaySessionInvokeTest.disconnectReportsUnknownOutcomeForFireAndForgetRpc). Tests neutralize runtime background work (cancel+join the runtime scope) before arming the registry and scripting lifecycle steps, and add regression coverage for the auto-connect intent claim. Proof: refresh flake reproduced at iteration 1 under taskset -c 0,1 on a Blacksmith Linux box; post-fix 3 pinned stress rounds (120/150 looped iterations) plus full :app:testPlayDebugUnitTest (109 classes, 0 failures) and :app:ktlintCheck green on the same box. * chore(i18n): resync native inventory line positions after NodeRuntime edits
…plicit intents (openclaw#101799) * fix(android): keep cold-start gateway auto-connect from overriding explicit intents NodeRuntime's init-time auto-connect now atomically claims the first gateway lifecycle intent (CAS 0->1) and stands down permanently when any explicit connect/disconnect/switch intent already exists, so a late discovery emission can no longer override a user decision. This was also the root cause of the CI-only flakes in GatewayBootstrapAuthTest (refreshGatewayConnection_* at :616/:627 and switchToUndiscoveredGateway* on PRs openclaw#101002/openclaw#101387/openclaw#101396). GatewaySession.Connection.sendRequestFrame now starts its response watcher with CoroutineStart.ATOMIC: disconnect teardown cancels connectionJob right after failPending(), and a DEFAULT-start watcher still queued for dispatch was cancelled without running, silently dropping the terminal UNAVAILABLE onError owed to fire-and-forget callers (root cause of the flaky GatewaySessionInvokeTest.disconnectReportsUnknownOutcomeForFireAndForgetRpc). Tests neutralize runtime background work (cancel+join the runtime scope) before arming the registry and scripting lifecycle steps, and add regression coverage for the auto-connect intent claim. Proof: refresh flake reproduced at iteration 1 under taskset -c 0,1 on a Blacksmith Linux box; post-fix 3 pinned stress rounds (120/150 looped iterations) plus full :app:testPlayDebugUnitTest (109 classes, 0 failures) and :app:ktlintCheck green on the same box. * chore(i18n): resync native inventory line positions after NodeRuntime edits
Related: #100699
What Problem This Solves
Android's tap-to-expand link-preview cards landed text-only in #100898; this delivers the declared og:image follow-up, matching the iOS sibling (#101387).
Why This Change Was Made
The expanded card now loads the OpenGraph image through the same locked-down OkHttp fetcher as the metadata — no new dependency, no ambient traffic. The image request runs only on the post-expansion path with Loaded metadata; the image URL independently passes the non-public-host policy (DNS-pinned client) before any request. Image mode refactors the fetch into one shared body path with per-mode rules:
image/jpeg|png|webpallowlist, 1 MiB hard cap (oversized rejected, not truncated), same redirect/deadline/no-cookie contract. A review-hardening round added byte-level format sniffing so a spoofed content-type cannot smuggle another decoder path. Decoding is bounds-first withinSampleSizetargeting ≤600px, with Runtime/OOM guards; failures cache negatively and the card stays text-only. Thumbnails render decorative (no content description) at ≤120dp; text renders immediately with no reserved placeholder, keeping failed/text-only cards compact at the cost of one bounded shift when an image arrives.User Impact
Android link-preview cards show the page's image when available, under the same zero-ambient-fetch contract.
Evidence
ChatLinkPreviewTest— 22 tests green: post-expansion-only fetch gating, host policy on image URLs, MIME + byte-format spoof rejection, size cap, redirect rules in image mode, downsampling bounds, corruption → negative cache, cache-hit request counting.corepack pnpm native:i18n:syncrun.