Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .agents/skills/verify-deepseekbot/features/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ One file per user-facing feature. Each file has four sections: `Sub-features`, `
| Stop a working Bot (Web Client) | yes | `scripts/e2e-web-stop.mjs` | [bot-stop.md](bot-stop.md) |
| Phone pairing and paired devices | no | `scripts/e2e-mobile-pairing-web.mjs`, `scripts/e2e-device-pairing.mjs`, `scripts/e2e-mobile-sim.mjs`, `scripts/e2e-mobile-pair-android.mjs` | [phone-pairing.md](phone-pairing.md) |
| Phone Chats drawer views and Android Host accent | no | none (shared-device native path) | [phone-drawer-views.md](phone-drawer-views.md) |
| Phone Chats swipe actions and Remote Host section creation | no | none (shared-device native path) | [phone-chat-row-actions.md](phone-chat-row-actions.md) |
| Native mobile message composer | no (except Bot reply) | none (shared-device native path) | [phone-composer.md](phone-composer.md) |
| Native mobile chat backgrounds | no (except live-reply regression) | none (shared-device native path) | [phone-chat-backgrounds.md](phone-chat-backgrounds.md) |
| Android launch, sheets, shell and chat presentation | no | Launch: queued native check; interactions: `scripts/e2e-mobile-android-interactions.mjs` | [phone-android-interactions.md](phone-android-interactions.md) |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Phone Chats row actions and Host sections

## Sub-features

- `swipe`: Host DM/Channel rows reveal Pin/Unpin, Add to section and Mute/Unmute; full swipe does not execute. Vertical scrolling and iOS left-edge drawer ownership remain intact.
- `menu`: the native row menu and accessibility actions use the same callbacks; Mark as read remains available when unread. iOS conversation preview still opens the intended chat once.
- `sections`: the native sheet reads the captured Remote Host's roster and assigns an existing section via `channelAssign`. New section uses `sectionCreate`, then the returned ID with `channelAssign`. No device-local section persistence.
- `recovery`: creation failure preserves the name; assignment failure preserves the confirmed section ID and retries assignment only; refresh failure retries refresh only. Host changes hide old choices and refuse continuation. An already-sent write stays on its original Host.

## How to get to it (user POV)

Open Chats with a paired Host and a DM or group Channel. Swipe a row left or open its actions menu. Choose Add to section, select an existing section or tap New section, enter a name and tap Create and add.

## Driving it with verify-app

Use the assigned [shared device QA](../../../../docs/agents/device-qa.md) runner and [Windows Android lane](../../../../docs/agents/android-device-qa.md). No model is needed. Use two disposable paired Hosts with neutral names and distinct sections; seed a DM, unread conversation and group Channel through existing CLI operations. Record PR/batch SHA, binary provenance, OS, viewport and actual OS text category/percentage.

1. Capture base and candidate on iPhone and Android at default/intermediate/maximum system text, light/dark, matching locale, viewport and test data. Capture closed row, revealed actions, open menu, section chooser, new-section keyboard and retry states. Web output is supplementary only.
2. Swipe `conversation-row-<key>` left outside the edge. Verify exactly three actions, no execution on a full swipe, and that each tap closes the rail without opening the conversation. Exercise Pin/Unpin and Mute/Unmute via both swipe and the menu; read the Host's roster/mute facts and compare after refresh/relaunch. Cloud rows and Bots without an existing DM must not receive Host actions.
3. On iOS start a rightward swipe inside 24 points (`EDGE_WIDTH`), just inside/outside its boundary, over multiple row positions. The drawer must win inside the zone; row swipe cannot activate there in either direction. Check vertical scroll, swipe-close and tap-close outside the edge. Long-press for the existing chat preview and open it; one tap/preview commit opens one destination.
4. With VoiceOver/TalkBack, open the row's named actions menu and run each action without swiping. Check row accessibility actions too; hidden rail buttons must not duplicate focus stops. Mark as read remains available for an unread row. Use Reduce Motion and Android ripple; repeat long names and orientation changes.
5. Add to section opens the owning Host's roster sections. Choose one and read `roster-get` on that Host: the Channel belongs to the selected section. Repeat for a Bot DM and a group. Desktop changes must appear through the existing refresh/subscription path. Collapsed sections/pins may affect where Chats shows the row.
6. On an empty section list, New section must remain available. Enter a long localized name with the actual soft keyboard, CJK composition, caret movement and live default→maximum→default size changes. Reach Create and add and Back without hiding text under the keyboard. Verify exactly one section and the membership on the originating Host. Reject whitespace; cancel before submit writes nothing. Reopen and confirm Host persistence.
7. Delay/fail `channelAssign` after successful `sectionCreate` in a disposable QA transport. The sheet shows the saved name and assignment error. Retry must use that ID, never another create; count sections on the Host. Fail refresh after assignment: Retry must not repeat writes. A failed create retains the draft and offers Back to inspect refreshed sections. Deterministic transport tests cover exact call ordering; screenshots alone cannot prove it.
8. Switch/unpair the owning Host while the sheet is open and during a delayed create. Old choices disappear and further actions refuse; no assignment goes to the new Host. A creation already accepted by the original Host may remain there. Reopen from the new Host and see only its sections. Restore device settings and remove only this task's disposable fixtures.

## Gotchas

- Native iPhone/Android gestures, native menus, keyboard clearance, screen-reader focus and large-text geometry remain unrun until the designated runner records them; unit tests mock native adapters.
- `sectionCreate` has no idempotency key. A lost creation response requires inspecting the Host list before a fresh create; the confirmed-create/failed-assign path has a safe ID-preserving retry.
- This flow creates and assigns sections only. Rename/delete/reorder and cross-Host aggregation are out of scope.
- No shared devices, Metro, QA Hosts or builds may start outside the owner-cut batch. The Windows machine cannot substitute source tests for iPhone acceptance.
38 changes: 38 additions & 0 deletions .github/pr-screenshots/2552-android/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# PR2552 Android native evidence — PARTIAL

Actual run: 2026-10-22, Android 16 arm64 physical phone, 1220 × 2712 screenshot pixels. This is development-native behavior, not Release performance, iOS, TalkBack or Human acceptance.

## Exact inputs and provenance

- Baseline main: `897e9334768baf26547eb155f9ab1b3e7a0ee61f`.
- Combined candidate: `8e09ba57d367dff346a4ab5f3c5d53e5c32c90e6`.
- PR2551: `5df949ff7fad82f128609a858277f161df484bcb` (tests/docs; streaming fixes already on baseline).
- PR2552: `a0a3f17af55af20e48a8c4bb1d47430bda7b7b99`.
- PR2554: `571b4437b4a5c323d243a56e79d25d5bf85f82b8`.
- Both independently computed native fingerprints: `2cde0026048320af2a7fdcafdc10b68875aadd75` (211 sources). Expo58.0.17 / RN0.88.0 / React19.3.0. Reused compatible arm64 development APK, SHA256 `B3A5DF7CA0D0F1C393523BE945FD49EF7263110A6DAA5B89726073759CA9ED3A`, 115259560 bytes. Historical native-build Node24.16/24.21 provenance uncertainty remains; actual Host/Metro runtime explicitly Node24.21.0. No new native build in this run.
- Preparation: 20 files / 163 tests and mobile typecheck passed. Separate baseline/candidate root builds passed; one sequential Metro and isolated QA Hosts. These source/build results are not native acceptance.
- Official provider/model: `deepseek-official` / `deepseek-flash`, verified with actual phone composer → Host → visible reply, not API-only. USB loopback QA route does not prove tailnet or QR scanning.

## PR2552 — PARTIAL; native operations and canonical ownership sampled

PASS sampled: full left swipe exposed actions and left canonical roster unchanged. Explicit native pin/mute/unpin/unmute changed the intended DM canonical fields. Native Android overflow menu also opened for a group. Empty section chooser worked; actual soft-keyboard pinyin composition selected `测试`, followed by `2552`; field and create control remained visible above keyboard. Create+assign produced exactly one `测试2552` section with the intended DM; pin was retained per this frozen PR's original contract. Later group assignment added the group to the same canonical section. Unpin/unmute preserved section membership.

Capture qualification: at07:31:47.306Z, about1.4s after create tap, the create sheet showed the selected name and a `重试` button without a visible error; the07:32:25 snapshot was back on Chats and Host state was successful. Source selects the Retry label whenever `state.selected` exists, including intermediate assignment. This early frame alone neither proves a persistent failure nor verifies the deliberate failure/retry journey. Preserve it as a transient-state observation.

Host switch: unsent draft `255299` on QA Host A was dismissed by switching to the other owned QA Host. That Host chooser exposed only `Baseline Only`; canonical state showed no `255299` section on either Host and no cross-Host assignment. This is an unsent-draft switch case, not delayed in-flight create/refusal verification.

UNTESTED: controlled create-success/assignment-failure retry, refresh failure, offline draft retention, in-flight Host refusal, TalkBack/hidden-rail focus, Reduce Motion, unread mark-read, full font/theme/rotation and form-caret matrix. Native labels sampled only. New organization design, Organize mode, Pinned grid and unpin-on-assign are excluded; original pin-preserving behavior cannot qualify the newer spec.

cjk.mp4 is the first59seconds of actual soft-keyboard composition at original speed. It ends before submission and does not prove successful create/assign; Host facts and subsequent snapshots establish that separately. created.png is the early selected-name/Retry intermediate state; it must not be captioned final failure or final success.

Status/system-navigation pixels cropped for privacy. No generated/reconstructed UI. PNGs reviewed individually through labeled contact sheets; recording frames sampled every5s across their full selected interval. No personal notification or credential visible in reviewed frames. Public clips only contain designated QA journeys; raw originals remain private. This sampling is not frame-by-frame privacy certification.

## Restoration and exclusions

Original development APK restored with install-r and pullback SHA256 `51602EFA76CF63081C664BF9F53B857F843F91B377F99EFDCA6DC699C9809766` matching backup. All eight recorded settings and original ADB reverse list matched; own pairings removed and all three issued credentials revoked. Two original offline Host entries remain and phone preferences were all true. Pre-run drawer-host IDs were missing, so exact original-pairing ID comparison is unavailable; earlier `exactMatch=false` was an invalid empty-baseline comparison, not proof of data loss. Original offline Host copies remain pending. No uninstall, pm-clear or production app changes.

Own Host/Metro processes, descendants, ports and recorders were stopped. Lease and heavy slot released07:53:03.733Z. Evidence: restore-device.json, cleanup-runtime.json, recorders-cleanup.json, resource-release.json and pairings-restore-qualified.json. Global ADB untouched.

Telemetry2570 remained BLOCKED: no independent production-egress isolation or dedicated synthetic container. No analytics configuration, interception, statistics-file mutation or personal opt-out operation occurred. Hermes2565, HostSettings2564, grid2574, Video and native splash2579 were excluded. Splash2579 is accepted for a future main batch containing merge55fe0fa36669e21d343bec7e417b2387d239118f and requires a new native APK; old binary/Metro cannot verify it.

Public images are pixel crops removing status/navigation bars only, with hashes and source binding. Raw logs, identifiers, private profiles, XML and unreviewed frames remain private. Public publication status is tracked in the sole queue; local assets alone do not complete PR evidence delivery.
Binary file added .github/pr-screenshots/2552-android/before.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/pr-screenshots/2552-android/chooser.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/pr-screenshots/2552-android/cjk.mp4
Binary file not shown.
Binary file added .github/pr-screenshots/2552-android/cjk.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/pr-screenshots/2552-android/created.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/pr-screenshots/2552-android/group.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions .github/pr-screenshots/2552-android/hashes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
[
{
"file": "before.png",
"bytes": 64207,
"sha256": "7d2f7622761565198114ef91868798f0d1e4dd0235d36f8cdc8909200b82e42e",
"processing": "Original1220x2712 crop x0/y130/w1220/h2530 only."
},
{
"file": "chooser.png",
"bytes": 65419,
"sha256": "cce7481850f6bfea814de0c4204f2e52cd9cacde8a79f894b9ab5c2885ed22eb",
"processing": "Original1220x2712 crop x0/y130/w1220/h2530 only."
},
{
"file": "cjk.mp4",
"bytes": 149555,
"sha256": "e82574ecbd668d8daeae14ea6f8677aa3ceef66f22786a69743f43a6892bc924",
"processing": "Original1220x2712 crop x0/y130/w1220/h2530, scale610x1264, H264, no audio, original playback speed."
},
{
"file": "cjk.png",
"bytes": 136976,
"sha256": "3484cbfcf08337ea6ce2d7dae1ca7f1daba34da8937c2ab05aa58db95fcf88eb",
"processing": "Original1220x2712 crop x0/y130/w1220/h2530 only."
},
{
"file": "created.png",
"bytes": 51583,
"sha256": "85d20d827d13af32c3a28bd2c67e336ccb10802ae753cfbea690c998dc5c8d77",
"processing": "Original1220x2712 crop x0/y130/w1220/h2530 only."
},
{
"file": "group.png",
"bytes": 58820,
"sha256": "dd42a7899f8affba7e15855cb6759781646fd2e100164ffb488242646ca79af9",
"processing": "Original1220x2712 crop x0/y130/w1220/h2530 only."
},
{
"file": "menu.png",
"bytes": 118469,
"sha256": "87ffbcd1eee4c14ae4779bc744e1a125140523e4ac5ab172a34be0865a1eb515",
"processing": "Original1220x2712 crop x0/y130/w1220/h2530 only."
},
{
"file": "other-host.png",
"bytes": 59894,
"sha256": "9ebaa9ac6f8a81c64e07729b60fe58bb9a4e7ccaa8f7984309c640afbbf73a53",
"processing": "Original1220x2712 crop x0/y130/w1220/h2530 only."
},
{
"file": "swipe.png",
"bytes": 84456,
"sha256": "1e9dcf42456a7c1edc172777332012f9389f02c36658e414e1eaca99492192d1",
"processing": "Original1220x2712 crop x0/y130/w1220/h2530 only."
}
]
Binary file added .github/pr-screenshots/2552-android/menu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/pr-screenshots/2552-android/swipe.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 0 additions & 5 deletions .github/pr-screenshots/2554-android/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ Actual run: 2026-10-22, Android 16 arm64 physical phone, 1220 × 2712 screenshot
- Preparation: 20 files / 163 tests and mobile typecheck passed. Separate baseline/candidate root builds passed; one sequential Metro and isolated QA Hosts. These source/build results are not native acceptance.
- Official provider/model: `deepseek-official` / `deepseek-flash`, verified with actual phone composer → Host → visible reply, not API-only. USB loopback QA route does not prove tailnet or QR scanning.


## PR2554 — sampled geometry improved; full acceptance remains PARTIAL

Baseline and candidate share the same HarborBot/42 data for row captures. Default/intermediate1.3 and extra2.0 stress light/dark captured. Baseline2.0 places title, time and preview on separate lines. Candidate places title/time on the same horizontal line with preview/status below and real PR2552 trailing menu. At2.0 dark, title/time are still truncated; this is not a full-content-visibility pass.
Expand All @@ -22,9 +21,6 @@ Actual OEM maximum was selected on the system font slider: label200% maps to And

Live font changes produced Expo Router linking/navigation warnings in both sources. Warnings remain visible in published full-app crops, with no attribution to these PRs. Some warnings overlap bottom navigation. Long-title row opening, complete accessibility and iOS/Human acceptance remain untested.




Status/system-navigation pixels cropped for privacy. No generated/reconstructed UI. PNGs reviewed individually through labeled contact sheets; recording frames sampled every5s across their full selected interval. No personal notification or credential visible in reviewed frames. Public clips only contain designated QA journeys; raw originals remain private. This sampling is not frame-by-frame privacy certification.

## Restoration and exclusions
Expand All @@ -36,4 +32,3 @@ Own Host/Metro processes, descendants, ports and recorders were stopped. Lease a
Telemetry2570 remained BLOCKED: no independent production-egress isolation or dedicated synthetic container. No analytics configuration, interception, statistics-file mutation or personal opt-out operation occurred. Hermes2565, HostSettings2564, grid2574, Video and native splash2579 were excluded. Splash2579 is accepted for a future main batch containing merge55fe0fa36669e21d343bec7e417b2387d239118f and requires a new native APK; old binary/Metro cannot verify it.

Public images are pixel crops removing status/navigation bars only, with hashes and source binding. Raw logs, identifiers, private profiles, XML and unreviewed frames remain private. Public publication status is tracked in the sole queue; local assets alone do not complete PR evidence delivery.

Loading
Loading