diff --git a/.github/pr-screenshots/tob-agent-health/01-member-agent.png b/.github/pr-screenshots/tob-agent-health/01-member-agent.png new file mode 100644 index 0000000000..48593b30a7 Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/01-member-agent.png differ diff --git a/.github/pr-screenshots/tob-agent-health/01-request.gesture-telemetry.json b/.github/pr-screenshots/tob-agent-health/01-request.gesture-telemetry.json new file mode 100644 index 0000000000..94471579c5 --- /dev/null +++ b/.github/pr-screenshots/tob-agent-health/01-request.gesture-telemetry.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "generatedAt": "2026-10-18T01:53:49.571Z", + "events": [ + { + "kind": "tap", + "tMs": 1696.541015625, + "x": 201, + "y": 528, + "referenceWidth": 402, + "referenceHeight": 874 + } + ] +} diff --git a/.github/pr-screenshots/tob-agent-health/01-request.mp4 b/.github/pr-screenshots/tob-agent-health/01-request.mp4 new file mode 100644 index 0000000000..a380a9abac Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/01-request.mp4 differ diff --git a/.github/pr-screenshots/tob-agent-health/02-request-sent.png b/.github/pr-screenshots/tob-agent-health/02-request-sent.png new file mode 100644 index 0000000000..73a085ae5c Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/02-request-sent.png differ diff --git a/.github/pr-screenshots/tob-agent-health/02-result.gesture-telemetry.json b/.github/pr-screenshots/tob-agent-health/02-result.gesture-telemetry.json new file mode 100644 index 0000000000..62389ac279 --- /dev/null +++ b/.github/pr-screenshots/tob-agent-health/02-result.gesture-telemetry.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "generatedAt": "2026-10-18T01:54:21.294Z", + "events": [ + { + "kind": "tap", + "tMs": 1774.493896484375, + "x": 201, + "y": 361, + "referenceWidth": 402, + "referenceHeight": 874 + } + ] +} diff --git a/.github/pr-screenshots/tob-agent-health/02-result.mp4 b/.github/pr-screenshots/tob-agent-health/02-result.mp4 new file mode 100644 index 0000000000..ba3ef5427e Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/02-result.mp4 differ diff --git a/.github/pr-screenshots/tob-agent-health/03-denied.gesture-telemetry.json b/.github/pr-screenshots/tob-agent-health/03-denied.gesture-telemetry.json new file mode 100644 index 0000000000..750e1ea3c7 --- /dev/null +++ b/.github/pr-screenshots/tob-agent-health/03-denied.gesture-telemetry.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "generatedAt": "2026-10-18T01:56:25.945Z", + "events": [ + { + "kind": "tap", + "tMs": 1769.397705078125, + "x": 201, + "y": 696, + "referenceWidth": 402, + "referenceHeight": 874 + } + ] +} diff --git a/.github/pr-screenshots/tob-agent-health/03-denied.mp4 b/.github/pr-screenshots/tob-agent-health/03-denied.mp4 new file mode 100644 index 0000000000..443ed88698 Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/03-denied.mp4 differ diff --git a/.github/pr-screenshots/tob-agent-health/03-result.png b/.github/pr-screenshots/tob-agent-health/03-result.png new file mode 100644 index 0000000000..1737d3c327 Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/03-result.png differ diff --git a/.github/pr-screenshots/tob-agent-health/04-restart-results.gesture-telemetry.json b/.github/pr-screenshots/tob-agent-health/04-restart-results.gesture-telemetry.json new file mode 100644 index 0000000000..7e68f87f43 --- /dev/null +++ b/.github/pr-screenshots/tob-agent-health/04-restart-results.gesture-telemetry.json @@ -0,0 +1,20 @@ +{ + "version": 1, + "generatedAt": "2026-10-18T01:58:39.612Z", + "events": [ + { + "kind": "scroll", + "tMs": 137, + "x": 201, + "y": 721, + "x2": 201, + "y2": 153, + "referenceWidth": 402, + "referenceHeight": 874, + "durationMs": 400, + "contentDirection": "down", + "amount": 0.65, + "pixels": 568 + } + ] +} diff --git a/.github/pr-screenshots/tob-agent-health/04-restart-results.mp4 b/.github/pr-screenshots/tob-agent-health/04-restart-results.mp4 new file mode 100644 index 0000000000..004dd979d5 Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/04-restart-results.mp4 differ diff --git a/.github/pr-screenshots/tob-agent-health/04-result-visible.png b/.github/pr-screenshots/tob-agent-health/04-result-visible.png new file mode 100644 index 0000000000..9dc1632c4c Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/04-result-visible.png differ diff --git a/.github/pr-screenshots/tob-agent-health/05-denied-maximum-dark.png b/.github/pr-screenshots/tob-agent-health/05-denied-maximum-dark.png new file mode 100644 index 0000000000..20b2257308 Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/05-denied-maximum-dark.png differ diff --git a/.github/pr-screenshots/tob-agent-health/06-zero-execution-maximum-dark.png b/.github/pr-screenshots/tob-agent-health/06-zero-execution-maximum-dark.png new file mode 100644 index 0000000000..7c181e0061 Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/06-zero-execution-maximum-dark.png differ diff --git a/.github/pr-screenshots/tob-agent-health/07-restart-denied.png b/.github/pr-screenshots/tob-agent-health/07-restart-denied.png new file mode 100644 index 0000000000..341fbd7903 Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/07-restart-denied.png differ diff --git a/.github/pr-screenshots/tob-agent-health/08-signed-out.png b/.github/pr-screenshots/tob-agent-health/08-signed-out.png new file mode 100644 index 0000000000..71c8f61970 Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/08-signed-out.png differ diff --git a/.github/pr-screenshots/tob-agent-health/README.md b/.github/pr-screenshots/tob-agent-health/README.md new file mode 100644 index 0000000000..569cc0bc3d --- /dev/null +++ b/.github/pr-screenshots/tob-agent-health/README.md @@ -0,0 +1,27 @@ +# T3 fixed health check — native UAT evidence + +- Runtime: `8586130e5303d100e47f9f29d91e3e8cf1556012`; batch later fast-forwarded to `81b98eafc` for three inherited evidence JSON formatting changes only (no runtime changes). +- Installed SDK58 native binary: `494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b`; no native inputs changed, no rebuild. +- TOB service: `23db30d9e34b8c51c72909b0a118e23d7dccf70e`, UAT version `eb945fb5-c38b-44de-8f28-dc90f17112af`, D1/Org/Channel schemas5/4/4. +- One assigned iOS Simulator; synthetic B is an ordinary organization member. Authentication fixture uses a real independent WorkOS UAT session; this is not new Hosted AuthKit/browser qualification. + +## Observed path + +1. Owner CLI provisioned a dedicated Agent in the shared workspace's health-mobile channel. Its local operator explicitly allowed B. +2. B tapped **Request health check**. A separate Node reference process read the public UAT channel, obtained current authorization, persisted its execution/result state, and returned platform/architecture/runtime with executionCount1. A fresh process replay reported executionCount0; server history contained one result for that request. +3. The local allow-list was cleared. B tapped the same action at maximum Dynamic Type; the next request produced LOCAL_POLICY_DENIED and executionCount0. Owner CLI independently read exactly two requests/two correlated results, with actual B and Agent authors. +4. Six default/intermediate/maximum × light/dark states exposed a reachable request action; owner creation controls were absent for B. No new text input was added. Large text scrolls long IDs and result text; screenshots05/06 show consecutive portions. +5. Cold restart, actual UI refresh and reload retained the same session/workspace and result history. Phone own logout was independently verified revoked, its latest refresh token rejected, local session cleared; A/B CLI sessions remained usable. + +## Files and limits + +- 01/02: member Agent and request acknowledgement; 03 is the initial history viewport (result body below the fold), 04 shows completed result. +- action-*: six request-control states;05/06 show maximum-text denial;07 shows denial after restart;08 signed out. +- Short videos01/03 show requests,02 the initial history load,04 scrolls to the retained result after restart. None records login credentials or token values. +- JSON files contain only bounded assertions; source49workerd/37Node/2wizard and mobile629passed/8skipped are separate evidence categories. + +First failures retained in task history: initial CLI fixture selected an organization B had not joined and was correctly denied; first deploy smoke timed out/failure without detailed classification, subsequent read-only smoke passed; mobile suite sandbox loopback EPERM resolved by permitted local listening; coldstart selector fired before UI ready; checkpoint during active history request returned SESSION_BUSY and later passed; inherited three evidence JSON files failed CI formatting, corrected without runtime change. Do not reinterpret those first attempts as successful. + +Own test Agent revoked and verified-revoked phone fixture removed. Light/large restored, own app/driver/Metro stopped, Batch18 released; shared resources preserved. UAT only, no Prod/merge. + +Not qualified: Android, physical phone, Human QA, new Hosted AuthKit, WebSocket, DSH adapter, model work, two isolated Hosts or arbitrary side effects. T3 and overall goal remain open. diff --git a/.github/pr-screenshots/tob-agent-health/action-appearance.json b/.github/pr-screenshots/tob-agent-health/action-appearance.json new file mode 100644 index 0000000000..1ea47549e9 --- /dev/null +++ b/.github/pr-screenshots/tob-agent-health/action-appearance.json @@ -0,0 +1,38 @@ +[ + { + "size": "large", + "theme": "light", + "requestReachable": true, + "ownerCreationAbsent": true + }, + { + "size": "large", + "theme": "dark", + "requestReachable": true, + "ownerCreationAbsent": true + }, + { + "size": "accessibility-medium", + "theme": "light", + "requestReachable": true, + "ownerCreationAbsent": true + }, + { + "size": "accessibility-medium", + "theme": "dark", + "requestReachable": true, + "ownerCreationAbsent": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "light", + "requestReachable": true, + "ownerCreationAbsent": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "dark", + "requestReachable": true, + "ownerCreationAbsent": true + } +] diff --git a/.github/pr-screenshots/tob-agent-health/action-default-dark.png b/.github/pr-screenshots/tob-agent-health/action-default-dark.png new file mode 100644 index 0000000000..c19108b280 Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/action-default-dark.png differ diff --git a/.github/pr-screenshots/tob-agent-health/action-default-light.png b/.github/pr-screenshots/tob-agent-health/action-default-light.png new file mode 100644 index 0000000000..e726a29fe2 Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/action-default-light.png differ diff --git a/.github/pr-screenshots/tob-agent-health/action-intermediate-dark.png b/.github/pr-screenshots/tob-agent-health/action-intermediate-dark.png new file mode 100644 index 0000000000..1a5b1a59c7 Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/action-intermediate-dark.png differ diff --git a/.github/pr-screenshots/tob-agent-health/action-intermediate-light.png b/.github/pr-screenshots/tob-agent-health/action-intermediate-light.png new file mode 100644 index 0000000000..e9c167fc6d Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/action-intermediate-light.png differ diff --git a/.github/pr-screenshots/tob-agent-health/action-maximum-dark.png b/.github/pr-screenshots/tob-agent-health/action-maximum-dark.png new file mode 100644 index 0000000000..4728cbe235 Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/action-maximum-dark.png differ diff --git a/.github/pr-screenshots/tob-agent-health/action-maximum-light.png b/.github/pr-screenshots/tob-agent-health/action-maximum-light.png new file mode 100644 index 0000000000..89c883521f Binary files /dev/null and b/.github/pr-screenshots/tob-agent-health/action-maximum-light.png differ diff --git a/.github/pr-screenshots/tob-agent-health/cli-uat.json b/.github/pr-screenshots/tob-agent-health/cli-uat.json new file mode 100644 index 0000000000..86d3dc00ec --- /dev/null +++ b/.github/pr-screenshots/tob-agent-health/cli-uat.json @@ -0,0 +1,8 @@ +{ + "stableRequestReplay": true, + "separateProcessExecutionOnce": true, + "memberAllowedByCloudButDeniedLocally": true, + "explicitLocalMemberGrant": true, + "exactThreeRequestsThreeResults": true, + "revokedAgentDenied": true +} diff --git a/.github/pr-screenshots/tob-agent-health/mobile-process.json b/.github/pr-screenshots/tob-agent-health/mobile-process.json new file mode 100644 index 0000000000..71f2be2805 --- /dev/null +++ b/.github/pr-screenshots/tob-agent-health/mobile-process.json @@ -0,0 +1,5 @@ +{ + "firstExecution": 1, + "freshProcessReplay": 0, + "processed": 1 +} diff --git a/.github/pr-screenshots/tob-agent-health/mobile-readback.json b/.github/pr-screenshots/tob-agent-health/mobile-readback.json new file mode 100644 index 0000000000..9bb7751708 --- /dev/null +++ b/.github/pr-screenshots/tob-agent-health/mobile-readback.json @@ -0,0 +1,8 @@ +{ + "exactFourMessages": true, + "phoneMemberIdentity": true, + "requestResultCorrelation": true, + "completedOnce": true, + "localDenialZeroExecution": true, + "independentCliSessions": true +} diff --git a/.github/pr-screenshots/tob-channel-agents/01-agent-entry.png b/.github/pr-screenshots/tob-channel-agents/01-agent-entry.png new file mode 100644 index 0000000000..3e8144e9ec Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/01-agent-entry.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/02-created-maximum-dark.png b/.github/pr-screenshots/tob-channel-agents/02-created-maximum-dark.png new file mode 100644 index 0000000000..2a8b7749f6 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/02-created-maximum-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/03-credential-handoff-safe.png b/.github/pr-screenshots/tob-channel-agents/03-credential-handoff-safe.png new file mode 100644 index 0000000000..5a736c8812 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/03-credential-handoff-safe.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/04-phone-agent-reply.png b/.github/pr-screenshots/tob-channel-agents/04-phone-agent-reply.png new file mode 100644 index 0000000000..2b083ba009 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/04-phone-agent-reply.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/05-restart-retained-handoff.png b/.github/pr-screenshots/tob-channel-agents/05-restart-retained-handoff.png new file mode 100644 index 0000000000..e7e5d40688 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/05-restart-retained-handoff.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/06-revoke-maximum.png b/.github/pr-screenshots/tob-channel-agents/06-revoke-maximum.png new file mode 100644 index 0000000000..acede06d52 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/06-revoke-maximum.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/07-revoked-maximum.png b/.github/pr-screenshots/tob-channel-agents/07-revoked-maximum.png new file mode 100644 index 0000000000..f5d2078ad2 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/07-revoked-maximum.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/08-signed-out.png b/.github/pr-screenshots/tob-channel-agents/08-signed-out.png new file mode 100644 index 0000000000..b2c73cf9f7 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/08-signed-out.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/README.md b/.github/pr-screenshots/tob-channel-agents/README.md new file mode 100644 index 0000000000..b5456de972 --- /dev/null +++ b/.github/pr-screenshots/tob-channel-agents/README.md @@ -0,0 +1,24 @@ +# Channel Agent native UAT evidence + +Batch17, 2026-10-18. Product/runtime `dc3ee2f09064de7e96169199c93a5cc68da400ea`, integrated batch same SHA. Initial `f25f5988a` differed only by one source-policy-prohibited comment; it was removed before captures and the app was cold-started. Signed native binary `494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b`; no native changes/build/erase. Service runtime `31e3a4a2880c05b670c2194d6b5a994dacfa297e`, UAT schema D1/Org/Channel5/4/3. Prod untouched; all PRs remain Draft/unmerged. + +## Observed behavior + +- `01-agent-entry`: owner channel Agent entry, before creating the test actor. +- `form-*`: six actual light/dark × default/intermediate/maximum text cases. Draft `Mobile echo` and keyboard focus retained. At maximum, input y217..274 and Create bottom365 are clear of keyboard top529. See `form-appearance-checks.json`. +- `02-created-maximum-dark`: phone created the channel Agent; after creation, the form scrolls to its top confirmation. +- `03-credential-handoff-safe`: safe management UI after explicit copy. Recording was stopped before copy; the copied credential went straight to an owner-only local file, was parsed/target-checked, and the simulator clipboard was cleared. No credential is in these artifacts. +- `04-phone-agent-reply`: phone sent `echo: Hello from the UAT phone`; independent reference Agent process read through public UAT HTTP and wrote its own author identity. Formal CLI read exactly the Human request and one Agent reply. A fresh second process produced zero new replies. See `mobile-readback.json`. +- `05-restart-retained-handoff`: cold-start and actual Refresh session retained the same private handoff. A second explicit copy was privately compared byte-for-byte as parsed data, then clipboard cleared again. The latest refresh token changed, with the same session identity. +- `06-revoke-maximum` / `07-revoked-maximum`: owner reached and used Revoke agent at maximum text size. Old credential read and send both returned `AGENT_ACCESS_DENIED`; see `mobile-revocation.json`. +- `08-signed-out`: local phone tokens removed, own remote session absent, latest refresh rejected, all pre-existing independent sessions preserved. + +Recordings: `create-agent.mp4`, `phone-agent-reply.mp4`, `restart-and-revoke.mp4` (restart/refresh portion only; recording stopped before copy), `revoke-agent.mp4`. Originals remain local; committed copies are 402px/12fps without audio. + +## Limits and first failures + +This is an unattended synthetic UAT session driven through the production UI/API; not a new Hosted AuthKit or Human QA result. It proves HTTP text identity/replay/revocation, not model work, shell execution, WebSocket, organization-wide Agent admission, two DSH Hosts, Android or physical iPhone. + +Initial driver attempts used wrong workspace label, tried an unavailable native Back control, and a hot refresh reset verified-session state. Navigation was corrected from actual snapshots and the final bundle cold-started before captures. Initial CI rejected a code comment; corrected exact-runtime CI39085993395 passed all applicable jobs. A redundant fixture cleanup request returned transport CHECK_FAILED after remote logout had already been independently verified; only the verified-revoked local phone fixture was removed. No cleanup success was inferred from that failed request. + +Batch17 released: light/large restored; own app/driver/Metro stopped. Original three QA untracked docs, installed app/Keychain, native Products/rollback, phone Metro and all Hosts preserved. The revoked Agent credential remains only in a private local test file. No secret was logged or published. diff --git a/.github/pr-screenshots/tob-channel-agents/create-agent.mp4 b/.github/pr-screenshots/tob-channel-agents/create-agent.mp4 new file mode 100644 index 0000000000..87ff890567 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/create-agent.mp4 differ diff --git a/.github/pr-screenshots/tob-channel-agents/form-appearance-checks.json b/.github/pr-screenshots/tob-channel-agents/form-appearance-checks.json new file mode 100644 index 0000000000..6b4ee7da53 --- /dev/null +++ b/.github/pr-screenshots/tob-channel-agents/form-appearance-checks.json @@ -0,0 +1,38 @@ +[ + { + "size": "large", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "large", + "theme": "dark", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-medium", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-medium", + "theme": "dark", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "dark", + "draftPreserved": true, + "focused": true + } +] diff --git a/.github/pr-screenshots/tob-channel-agents/form-default-dark.png b/.github/pr-screenshots/tob-channel-agents/form-default-dark.png new file mode 100644 index 0000000000..96800aac9b Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/form-default-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/form-default-light.png b/.github/pr-screenshots/tob-channel-agents/form-default-light.png new file mode 100644 index 0000000000..69de9bf16f Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/form-default-light.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/form-intermediate-dark.png b/.github/pr-screenshots/tob-channel-agents/form-intermediate-dark.png new file mode 100644 index 0000000000..5edd19e8e6 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/form-intermediate-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/form-intermediate-light.png b/.github/pr-screenshots/tob-channel-agents/form-intermediate-light.png new file mode 100644 index 0000000000..75bfdb81e3 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/form-intermediate-light.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/form-maximum-dark.png b/.github/pr-screenshots/tob-channel-agents/form-maximum-dark.png new file mode 100644 index 0000000000..6c1265828a Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/form-maximum-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/form-maximum-light.png b/.github/pr-screenshots/tob-channel-agents/form-maximum-light.png new file mode 100644 index 0000000000..4ad0bbc135 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/form-maximum-light.png differ diff --git a/.github/pr-screenshots/tob-channel-agents/mobile-readback.json b/.github/pr-screenshots/tob-channel-agents/mobile-readback.json new file mode 100644 index 0000000000..27171a43c4 --- /dev/null +++ b/.github/pr-screenshots/tob-channel-agents/mobile-readback.json @@ -0,0 +1,6 @@ +{ + "phoneIssuedAgentVisibleInCli": true, + "exactTwoMessageHistory": true, + "agentAuthorMatches": true, + "noDuplicateReply": true +} diff --git a/.github/pr-screenshots/tob-channel-agents/mobile-revocation.json b/.github/pr-screenshots/tob-channel-agents/mobile-revocation.json new file mode 100644 index 0000000000..0ca472db38 --- /dev/null +++ b/.github/pr-screenshots/tob-channel-agents/mobile-revocation.json @@ -0,0 +1,4 @@ +{ + "phoneRevokedOldCredentialReadDenied": true, + "phoneRevokedOldCredentialSendDenied": true +} diff --git a/.github/pr-screenshots/tob-channel-agents/phone-agent-reply.mp4 b/.github/pr-screenshots/tob-channel-agents/phone-agent-reply.mp4 new file mode 100644 index 0000000000..c719907d77 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/phone-agent-reply.mp4 differ diff --git a/.github/pr-screenshots/tob-channel-agents/restart-and-revoke.mp4 b/.github/pr-screenshots/tob-channel-agents/restart-and-revoke.mp4 new file mode 100644 index 0000000000..2356b2e38e Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/restart-and-revoke.mp4 differ diff --git a/.github/pr-screenshots/tob-channel-agents/revoke-agent.mp4 b/.github/pr-screenshots/tob-channel-agents/revoke-agent.mp4 new file mode 100644 index 0000000000..35beb93610 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-agents/revoke-agent.mp4 differ diff --git a/.github/pr-screenshots/tob-channel-guests/02-guest-entry.png b/.github/pr-screenshots/tob-channel-guests/02-guest-entry.png new file mode 100644 index 0000000000..714b4f3d08 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/02-guest-entry.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/03-invitation-created.png b/.github/pr-screenshots/tob-channel-guests/03-invitation-created.png new file mode 100644 index 0000000000..92094eabab Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/03-invitation-created.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/04-recipient-inbox.png b/.github/pr-screenshots/tob-channel-guests/04-recipient-inbox.png new file mode 100644 index 0000000000..401e095417 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/04-recipient-inbox.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/05-guest-channels.png b/.github/pr-screenshots/tob-channel-guests/05-guest-channels.png new file mode 100644 index 0000000000..a6e44daa2a Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/05-guest-channels.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/06-no-prejoin-history.png b/.github/pr-screenshots/tob-channel-guests/06-no-prejoin-history.png new file mode 100644 index 0000000000..82ad54557d Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/06-no-prejoin-history.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/10-restart-guest-history.png b/.github/pr-screenshots/tob-channel-guests/10-restart-guest-history.png new file mode 100644 index 0000000000..92ea4afb6c Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/10-restart-guest-history.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/11-revoked-phone-session.png b/.github/pr-screenshots/tob-channel-guests/11-revoked-phone-session.png new file mode 100644 index 0000000000..bfcb47b1b6 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/11-revoked-phone-session.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/12-owner-revoke-max.png b/.github/pr-screenshots/tob-channel-guests/12-owner-revoke-max.png new file mode 100644 index 0000000000..9e56f20a2c Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/12-owner-revoke-max.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/13-owner-revoked-max.png b/.github/pr-screenshots/tob-channel-guests/13-owner-revoked-max.png new file mode 100644 index 0000000000..8a747c7565 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/13-owner-revoked-max.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/README.md b/.github/pr-screenshots/tob-channel-guests/README.md new file mode 100644 index 0000000000..4e3ca94a5e --- /dev/null +++ b/.github/pr-screenshots/tob-channel-guests/README.md @@ -0,0 +1,31 @@ +# Direct channel guests — native UAT evidence + +Final mobile runtime: `bc08a47e6f060fe6caa6b879c4b2464e12d69e05`; compatible signed native binary: `494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b`. Shared iOS 26 Simulator, English, 402 × 874 logical pixels. Service `6226ec3af48d7c446c95421290aaa280ce8a7490`, Worker version `b8e22111-d975-4ad6-81b9-6d56e32fb84c`, D1/Org/Channel schema **5/4/2**. UAT only; no native rebuild, Prod changes or merge. + +## Observed behavior + +- Ordinary owner A issued a direct invitation to synthetic B from the phone. B accepted from its own phone inbox and opened Guest channels. Its organization selection was unchanged; no WorkOS membership was created in A's workspace. Sibling channels and the pre-join message were inaccessible. +- B sent `B joins only this channel from phone`; independent owner CLI read the exact author/text at sequence 2. Owner CLI revoked access; a replacement invitation was accepted through B's CLI to set up rejoin testing. The same phone session could read only after the new floor (2). A deliberate new phone send committed at sequence 3; owner CLI saw both sends and B saw only sequence 3. These are distinct operations across two grants, not duplicate delivery. +- B refreshed, cold-restarted, checked its saved session and opened the same guest channel with sequence 3. Owner CLI then revoked the active grant. Reload on the old phone session visibly returned `CHANNEL_ACCESS_DENIED`; independent B CLI was denied and its guest list omitted the channel. Already rendered, previously authorized text can remain on screen; the error proves the subsequent request was refused. +- A separate replacement grant was prepared via CLI. A's phone reached and used **Revoke channel access** at maximum text size. The row became Revoked; B's independent CLI again lost access. This proves the owner UI action separately from the earlier CLI-triggered revocation. +- Independent A/B phone sessions signed out through the UI. Each latest refresh token was rejected, its WorkOS session revoked and its local session removed; all pre-existing active sessions, including A/B CLI, remained intact. +- Six owner-invitation form and six guest-composer size/theme combinations retained exact draft and focus. The final maximum guest Send bottom was about 525px, above the predictive keyboard top at 529px; an actual send succeeded. Maximum owner revoke was reached through scrolling and operated. + +## Capture provenance + +| Files | Runtime / meaning | +| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `02-*`, `03-*`, `form-*`, `owner-invite.mp4` | `77cd444bffda36846838093ce6a25e17e7b7a951`: final channel-specific title/name and actual owner issuance; later changes affect accepted labels/composer spacing. | +| `04-*`, `05-*`, `06-*`, `recipient-accept.mp4` | `6f4d99fe3f2280584f26debefc26b53febc3a1c6`: real recipient acceptance and initial send. Video also includes the first failing composer matrix, not a final keyboard pass. | +| `message-*`, `10-*`–`13-*`, remaining videos | `bc08a47e6f060fe6caa6b879c4b2464e12d69e05`: corrected keyboard geometry, committed post-rejoin send, restart, old-phone refusal and owner revoke. Owner-revoke video ends during the request; `13-*` plus independent CLI readback prove completion. | +| `before-clipped-maximum-dark.png` | Earlier failing empty-history maximum-text composer; compare final `message-maximum-dark.png` at the same viewport/theme. | + +Videos are compressed to 402px / 12fps without audio. Captures contain only synthetic example.test users and test content; no credentials or invitation tokens. The [prior workspace entry](../tob-org-invitations/member-inbox.png) is a historical organization-only comparison, not a guest feature test. + +## First failures and limits + +The first form used a workspace title; corrected before issuance. The first empty-history maximum-text composer clipped input beneath the fixed header. A first spacing fix exposed the input but left Send below the prediction bar (bottom549 vs529); the final compact guest action and margin passed the full six-case matrix. An earlier large upward gesture dismissed the modal, so that recording/screenshot is not used as revocation proof. A premature generic wait missed a pending request; final completion uses the actual changed control plus canonical readback. These failures are retained in the task's local evidence, not presented as first-pass success. + +32 focused client/driver/style tests passed; service 41 workerd and 25 Node/CLI checks passed. Source/workerd cover idempotent retry and authorization failure paths. Native uncertain-response injection was not run. Synthetic sessions use the authorized UAT harness with normal server verification; this run does not repeat Hosted AuthKit login or test actual email delivery/new signup. Android, physical phone, Human QA, screen readers and non-Latin IME remain unqualified. Agents, WebSocket, identity-event revocation and two-Host communication are subsequent slices. + +After verification, large/light were restored; own app, driver and Metro stopped; revoked phone fixture removed. Existing app data, Keychain, independent CLI fixtures, other device lanes, native Products/rollback and all Hosts were preserved. diff --git a/.github/pr-screenshots/tob-channel-guests/before-clipped-maximum-dark.png b/.github/pr-screenshots/tob-channel-guests/before-clipped-maximum-dark.png new file mode 100644 index 0000000000..40dd61ab05 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/before-clipped-maximum-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/form-appearance-checks.json b/.github/pr-screenshots/tob-channel-guests/form-appearance-checks.json new file mode 100644 index 0000000000..6b4ee7da53 --- /dev/null +++ b/.github/pr-screenshots/tob-channel-guests/form-appearance-checks.json @@ -0,0 +1,38 @@ +[ + { + "size": "large", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "large", + "theme": "dark", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-medium", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-medium", + "theme": "dark", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "dark", + "draftPreserved": true, + "focused": true + } +] diff --git a/.github/pr-screenshots/tob-channel-guests/form-default-dark.png b/.github/pr-screenshots/tob-channel-guests/form-default-dark.png new file mode 100644 index 0000000000..e33ae0ff26 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/form-default-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/form-default-light.png b/.github/pr-screenshots/tob-channel-guests/form-default-light.png new file mode 100644 index 0000000000..16ba1d6fad Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/form-default-light.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/form-intermediate-dark.png b/.github/pr-screenshots/tob-channel-guests/form-intermediate-dark.png new file mode 100644 index 0000000000..d0d1b5dc12 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/form-intermediate-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/form-intermediate-light.png b/.github/pr-screenshots/tob-channel-guests/form-intermediate-light.png new file mode 100644 index 0000000000..c2898ba853 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/form-intermediate-light.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/form-maximum-dark.png b/.github/pr-screenshots/tob-channel-guests/form-maximum-dark.png new file mode 100644 index 0000000000..2f18b2b46b Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/form-maximum-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/form-maximum-light.png b/.github/pr-screenshots/tob-channel-guests/form-maximum-light.png new file mode 100644 index 0000000000..603c06f43c Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/form-maximum-light.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/keyboard-and-send.mp4 b/.github/pr-screenshots/tob-channel-guests/keyboard-and-send.mp4 new file mode 100644 index 0000000000..b7a33ad106 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/keyboard-and-send.mp4 differ diff --git a/.github/pr-screenshots/tob-channel-guests/message-appearance-checks.json b/.github/pr-screenshots/tob-channel-guests/message-appearance-checks.json new file mode 100644 index 0000000000..6b4ee7da53 --- /dev/null +++ b/.github/pr-screenshots/tob-channel-guests/message-appearance-checks.json @@ -0,0 +1,38 @@ +[ + { + "size": "large", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "large", + "theme": "dark", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-medium", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-medium", + "theme": "dark", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "dark", + "draftPreserved": true, + "focused": true + } +] diff --git a/.github/pr-screenshots/tob-channel-guests/message-default-dark.png b/.github/pr-screenshots/tob-channel-guests/message-default-dark.png new file mode 100644 index 0000000000..aa21bbf280 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/message-default-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/message-default-light.png b/.github/pr-screenshots/tob-channel-guests/message-default-light.png new file mode 100644 index 0000000000..6d0e69253c Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/message-default-light.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/message-intermediate-dark.png b/.github/pr-screenshots/tob-channel-guests/message-intermediate-dark.png new file mode 100644 index 0000000000..2662a308af Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/message-intermediate-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/message-intermediate-light.png b/.github/pr-screenshots/tob-channel-guests/message-intermediate-light.png new file mode 100644 index 0000000000..c5547ca881 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/message-intermediate-light.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/message-maximum-dark.png b/.github/pr-screenshots/tob-channel-guests/message-maximum-dark.png new file mode 100644 index 0000000000..3225ca5185 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/message-maximum-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/message-maximum-light.png b/.github/pr-screenshots/tob-channel-guests/message-maximum-light.png new file mode 100644 index 0000000000..16b5fece58 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/message-maximum-light.png differ diff --git a/.github/pr-screenshots/tob-channel-guests/owner-invite.mp4 b/.github/pr-screenshots/tob-channel-guests/owner-invite.mp4 new file mode 100644 index 0000000000..52432a822c Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/owner-invite.mp4 differ diff --git a/.github/pr-screenshots/tob-channel-guests/owner-revoke.mp4 b/.github/pr-screenshots/tob-channel-guests/owner-revoke.mp4 new file mode 100644 index 0000000000..fba59fc6c3 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/owner-revoke.mp4 differ diff --git a/.github/pr-screenshots/tob-channel-guests/recipient-accept.mp4 b/.github/pr-screenshots/tob-channel-guests/recipient-accept.mp4 new file mode 100644 index 0000000000..6960772e3a Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/recipient-accept.mp4 differ diff --git a/.github/pr-screenshots/tob-channel-guests/restart-and-revoke.mp4 b/.github/pr-screenshots/tob-channel-guests/restart-and-revoke.mp4 new file mode 100644 index 0000000000..991a13a631 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-guests/restart-and-revoke.mp4 differ diff --git a/.github/pr-screenshots/tob-channel-http/01-workspace-entry.png b/.github/pr-screenshots/tob-channel-http/01-workspace-entry.png new file mode 100644 index 0000000000..9c1951123e Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/01-workspace-entry.png differ diff --git a/.github/pr-screenshots/tob-channel-http/03-three-channels.png b/.github/pr-screenshots/tob-channel-http/03-three-channels.png new file mode 100644 index 0000000000..fbae8478ac Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/03-three-channels.png differ diff --git a/.github/pr-screenshots/tob-channel-http/06-cli-reply.png b/.github/pr-screenshots/tob-channel-http/06-cli-reply.png new file mode 100644 index 0000000000..221cec76bd Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/06-cli-reply.png differ diff --git a/.github/pr-screenshots/tob-channel-http/11-maximum-keyboard-light.png b/.github/pr-screenshots/tob-channel-http/11-maximum-keyboard-light.png new file mode 100644 index 0000000000..aeb4b1219e Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/11-maximum-keyboard-light.png differ diff --git a/.github/pr-screenshots/tob-channel-http/19-fixed-max-dark.png b/.github/pr-screenshots/tob-channel-http/19-fixed-max-dark.png new file mode 100644 index 0000000000..d942cee5bb Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/19-fixed-max-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-http/24-create-max-dark.png b/.github/pr-screenshots/tob-channel-http/24-create-max-dark.png new file mode 100644 index 0000000000..45ef0e24db Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/24-create-max-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-http/26-four-channels.png b/.github/pr-screenshots/tob-channel-http/26-four-channels.png new file mode 100644 index 0000000000..cc62cb74a7 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/26-four-channels.png differ diff --git a/.github/pr-screenshots/tob-channel-http/27-contrast-create-dark.png b/.github/pr-screenshots/tob-channel-http/27-contrast-create-dark.png new file mode 100644 index 0000000000..2cb1e541e9 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/27-contrast-create-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-http/28-contrast-create-light.png b/.github/pr-screenshots/tob-channel-http/28-contrast-create-light.png new file mode 100644 index 0000000000..9426ac9652 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/28-contrast-create-light.png differ diff --git a/.github/pr-screenshots/tob-channel-http/29-final-restart-session.png b/.github/pr-screenshots/tob-channel-http/29-final-restart-session.png new file mode 100644 index 0000000000..302ec01983 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/29-final-restart-session.png differ diff --git a/.github/pr-screenshots/tob-channel-http/30-signed-out.png b/.github/pr-screenshots/tob-channel-http/30-signed-out.png new file mode 100644 index 0000000000..31a5e7de90 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/30-signed-out.png differ diff --git a/.github/pr-screenshots/tob-channel-http/README.md b/.github/pr-screenshots/tob-channel-http/README.md new file mode 100644 index 0000000000..552c955e06 --- /dev/null +++ b/.github/pr-screenshots/tob-channel-http/README.md @@ -0,0 +1,33 @@ +# Cloud channel HTTP UAT — 2026-10-18 JST + +Final mobile runtime: `5d2ef0fe8a13654a75779ea0320394b13c00764c`. Compatible signed native build: `494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b`. Service runtime: `b26150224a60808d89daf7e9cd8863faf26ed75f`, UAT Worker version `f62d1003-7e9c-4924-a889-d06a27ec0427`, D1/Org/Channel schemas 4/3/1. + +Shared iPhone 17 Pro / iOS 26 Simulator only, English, 402×874 captures. No build, erase, physical phone, Host, Prod or merge action. Authentication uses an API-prepared synthetic ordinary-user session and the existing trusted configuration; this is not another Hosted AuthKit/PKCE or email-delivery test. + +## Observed behavior + +- CLI creates `general` and `research`, replays identical create/send operations without duplicate records, and reads durable history. The other user cannot read these channels, including by putting their IDs under the wrong organization URL. +- Actual phone UI creates `mobile-test`; independent formal CLI sees the exact organization/channel. Phone sends, CLI reads and replies, phone reloads the reply. The final CLI readback matches all seven message bodies, newlines and ordered sequences 1–7. Repeated identical text in sequences 6 and 7 is two deliberate sends with different operation keys, not a replay duplicate. +- Phone also creates `large-type` at maximum Dynamic Type. A's selected workspace now has four channels; B's has zero. A has three workspaces and B has one. +- Temporarily changing synthetic A's current WorkOS membership from owner to member makes a stale-owner-token channel creation fail with 403. Listing, reading and sending remain allowed. The operator restored and verified owner before native testing. No Human administrator role changed. +- Cold restart retains the saved session/selected workspace; server checks and refresh retain the verified ordinary-user role. Sign out revokes the phone session, rejects its latest refresh, removes local persisted/in-memory credentials, and retains configuration. Independent A and B CLI calls still work. The temporary phone credential file was removed after verification. +- The final six-case matrix covers standard (`large`), intermediate (`accessibility-medium`) and maximum (`accessibility-extra-extra-extra-large`) × light/dark. Live resizing retains the exact multiline draft and focus. At final maximum/dark, the complete Send button bottom is 521pt and the predictive keyboard begins at 529pt; the actual tap commits sequence 7. Native keyboard frames, not delayed scrolling, drive the list. + +## Captures and provenance + +- `before-workspace-entry.png` is the same selected workspace before the new channel entry, from the prior onboarding slice (`9f71dd3d9`). `01-workspace-entry.png` adds the entry at `7ceab0d27`. +- `03-three-channels.png` and `06-cli-reply.png` show the first HTTP path at `7ceab0d27`. `26-four-channels.png` is the later four-channel list at `f4dd6dc2f`. +- `11-maximum-keyboard-light.png` preserves the original covered caret/action failure. `19-fixed-max-dark.png` and `24-create-max-dark.png` preserve the later dark-input contrast failure; despite their working filenames, they are NOT final passing evidence. +- `27-contrast-create-dark.png` / `28-contrast-create-light.png` show themed creation input at `6704326e9`. No channel was created from that `contrast-check` draft; it was discarded on restart. +- `final-*.png`, `29-final-restart-session.png` and `30-signed-out.png` are final `5d2ef0fe8` evidence. The final composer matrix uses the same multiline draft in every case. Compared with the first failure, draft text and scroll/caret position differ; the corrected draft is longer and includes an explicit newline. These are a native behavioral comparison, not pixel-matched typography benchmarks. +- Recordings preserve real timing, including idle/tool pauses. Published copies use 12fps H.264 review encoding with unchanged chronology; originals remain local. `recordings.json` gives each duration/size. Preview sheets sample frames and are not extra test executions. `first-run.mp4` captures `7ceab0d27`; `keyboard-and-fonts.mp4` captures `f4dd6dc2f`. `final-session.mp4` spans the `6704326e9` contrast check and subsequent `5d2ef0fe8` short-label fix, final matrix, send, restart and sign-out; do not attribute its entire duration to the final head. + +## Retained failures and proof limits + +The first UAT CLI attempt failed during JWKS lookup before writes; replaying the same keys passed. Initial native keyboard handling covered the caret at maximum text size. Reusing the existing keyboard-form adapter fixed focus reveal; two-line action spacing and a concise Send label keep the full action above the predictive bar. Explicit theme foreground/placeholder colors fix black text in dark mode. + +The first repair recheck still used old JS because Metro was started with CI mode and file watching disabled. `stale-metro-recheck.mp4` is harness failure evidence, not proof of the repaired head. The runner restarted only its own Metro, then repeated on the loaded candidate. Two attempts to replace an existing long draft produced driver readback mismatches; that unsent draft was discarded through the UI. Fresh-field input and final exact server readback passed. One appearance transition screenshot was not used as final evidence. Formatting failures and fixes remain in CI history. + +Source checks: 30 workerd service tests, 23 Node/CLI/contracts, mobile 20 focused client/style tests, typechecks and applicable CI. Evidence does not establish Android native behavior, physical-device or Human visual acceptance, screen-reader/IME qualification, WebSocket delivery, invitations, Agents, history grants/rejoin, or cross-Host work. Current HTTP membership checks do not close the outstanding T1 provider-event/session-revocation gates. T1/T2 remain open. + +Light appearance and large text size were restored. The driver, app and owned Metro were stopped; shared original files/data/native rollback and other lanes were preserved. The UAT synthetic identities, four workspaces, four channels and independent CLI sessions remain for the next goal slice. diff --git a/.github/pr-screenshots/tob-channel-http/appearance-checks.json b/.github/pr-screenshots/tob-channel-http/appearance-checks.json new file mode 100644 index 0000000000..6b4ee7da53 --- /dev/null +++ b/.github/pr-screenshots/tob-channel-http/appearance-checks.json @@ -0,0 +1,38 @@ +[ + { + "size": "large", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "large", + "theme": "dark", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-medium", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-medium", + "theme": "dark", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "dark", + "draftPreserved": true, + "focused": true + } +] diff --git a/.github/pr-screenshots/tob-channel-http/before-workspace-entry.png b/.github/pr-screenshots/tob-channel-http/before-workspace-entry.png new file mode 100644 index 0000000000..8de8221ac3 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/before-workspace-entry.png differ diff --git a/.github/pr-screenshots/tob-channel-http/final-default-dark.png b/.github/pr-screenshots/tob-channel-http/final-default-dark.png new file mode 100644 index 0000000000..d7b81f1548 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/final-default-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-http/final-default-light.png b/.github/pr-screenshots/tob-channel-http/final-default-light.png new file mode 100644 index 0000000000..1165bedeed Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/final-default-light.png differ diff --git a/.github/pr-screenshots/tob-channel-http/final-intermediate-dark.png b/.github/pr-screenshots/tob-channel-http/final-intermediate-dark.png new file mode 100644 index 0000000000..70c09a942b Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/final-intermediate-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-http/final-intermediate-light.png b/.github/pr-screenshots/tob-channel-http/final-intermediate-light.png new file mode 100644 index 0000000000..f0ccb24a33 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/final-intermediate-light.png differ diff --git a/.github/pr-screenshots/tob-channel-http/final-maximum-dark.png b/.github/pr-screenshots/tob-channel-http/final-maximum-dark.png new file mode 100644 index 0000000000..4a634f8b61 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/final-maximum-dark.png differ diff --git a/.github/pr-screenshots/tob-channel-http/final-maximum-light.png b/.github/pr-screenshots/tob-channel-http/final-maximum-light.png new file mode 100644 index 0000000000..71d4579ee8 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/final-maximum-light.png differ diff --git a/.github/pr-screenshots/tob-channel-http/final-session-preview.png b/.github/pr-screenshots/tob-channel-http/final-session-preview.png new file mode 100644 index 0000000000..f2f68374ff Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/final-session-preview.png differ diff --git a/.github/pr-screenshots/tob-channel-http/final-session.mp4 b/.github/pr-screenshots/tob-channel-http/final-session.mp4 new file mode 100644 index 0000000000..34c23d8f5e Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/final-session.mp4 differ diff --git a/.github/pr-screenshots/tob-channel-http/first-run-preview.png b/.github/pr-screenshots/tob-channel-http/first-run-preview.png new file mode 100644 index 0000000000..4b2b16849d Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/first-run-preview.png differ diff --git a/.github/pr-screenshots/tob-channel-http/first-run.mp4 b/.github/pr-screenshots/tob-channel-http/first-run.mp4 new file mode 100644 index 0000000000..581751ccab Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/first-run.mp4 differ diff --git a/.github/pr-screenshots/tob-channel-http/keyboard-and-fonts-preview.png b/.github/pr-screenshots/tob-channel-http/keyboard-and-fonts-preview.png new file mode 100644 index 0000000000..02b04c3c9f Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/keyboard-and-fonts-preview.png differ diff --git a/.github/pr-screenshots/tob-channel-http/keyboard-and-fonts.mp4 b/.github/pr-screenshots/tob-channel-http/keyboard-and-fonts.mp4 new file mode 100644 index 0000000000..6fcbefafed Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/keyboard-and-fonts.mp4 differ diff --git a/.github/pr-screenshots/tob-channel-http/recordings.json b/.github/pr-screenshots/tob-channel-http/recordings.json new file mode 100644 index 0000000000..111c82e295 --- /dev/null +++ b/.github/pr-screenshots/tob-channel-http/recordings.json @@ -0,0 +1,18 @@ +{ + "final-session.mp4": { + "duration": "383.500000", + "size": "4336768" + }, + "first-run.mp4": { + "duration": "629.166667", + "size": "3473431" + }, + "keyboard-and-fonts.mp4": { + "duration": "164.166667", + "size": "1871892" + }, + "stale-metro-recheck.mp4": { + "duration": "265.333333", + "size": "2173105" + } +} diff --git a/.github/pr-screenshots/tob-channel-http/results.json b/.github/pr-screenshots/tob-channel-http/results.json new file mode 100644 index 0000000000..0de587cb58 --- /dev/null +++ b/.github/pr-screenshots/tob-channel-http/results.json @@ -0,0 +1,40 @@ +{ + "mobileRuntime": "5d2ef0fe8a13654a75779ea0320394b13c00764c", + "nativeRuntime": "494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b", + "serviceRuntime": "b26150224a60808d89daf7e9cd8863faf26ed75f", + "uatOnly": true, + "nativeRebuilt": false, + "organizationCounts": { + "a": 3, + "b": 1 + }, + "channelCounts": { + "aSelectedWorkspace": 4, + "bSelectedWorkspace": 0 + }, + "mobileCliExactMessages": 7, + "maximumKeyboardGeometry": { + "sendButtonBottom": 521, + "predictionBarTop": 529, + "passed": true + }, + "coldRestart": true, + "sessionRefresh": true, + "phoneSessionRevoked": true, + "latestPhoneRefreshRejected": true, + "localPhoneSessionRemoved": true, + "independentCliAAndBUsable": true, + "originalAppearanceRestored": "light", + "originalContentSizeRestored": "large", + "unverified": [ + "Android native", + "physical phone", + "Human visual QA", + "new Hosted AuthKit login", + "WebSocket", + "invitations", + "Agent credentials", + "cross-Host communication", + "history grants and membership rejoin" + ] +} diff --git a/.github/pr-screenshots/tob-channel-http/stale-metro-recheck-preview.png b/.github/pr-screenshots/tob-channel-http/stale-metro-recheck-preview.png new file mode 100644 index 0000000000..b17e6d79d4 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/stale-metro-recheck-preview.png differ diff --git a/.github/pr-screenshots/tob-channel-http/stale-metro-recheck.mp4 b/.github/pr-screenshots/tob-channel-http/stale-metro-recheck.mp4 new file mode 100644 index 0000000000..8a173ab498 Binary files /dev/null and b/.github/pr-screenshots/tob-channel-http/stale-metro-recheck.mp4 differ diff --git a/.github/pr-screenshots/tob-multi-user/01-saved-session.png b/.github/pr-screenshots/tob-multi-user/01-saved-session.png new file mode 100644 index 0000000000..31d361cb7c Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/01-saved-session.png differ diff --git a/.github/pr-screenshots/tob-multi-user/02-ordinary-user.png b/.github/pr-screenshots/tob-multi-user/02-ordinary-user.png new file mode 100644 index 0000000000..80e45bf6c2 Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/02-ordinary-user.png differ diff --git a/.github/pr-screenshots/tob-multi-user/03-workspace-list.png b/.github/pr-screenshots/tob-multi-user/03-workspace-list.png new file mode 100644 index 0000000000..03832e2590 Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/03-workspace-list.png differ diff --git a/.github/pr-screenshots/tob-multi-user/04-mobile-created.png b/.github/pr-screenshots/tob-multi-user/04-mobile-created.png new file mode 100644 index 0000000000..99dffa4ad9 Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/04-mobile-created.png differ diff --git a/.github/pr-screenshots/tob-multi-user/05-default-selected.png b/.github/pr-screenshots/tob-multi-user/05-default-selected.png new file mode 100644 index 0000000000..2c05327bd3 Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/05-default-selected.png differ diff --git a/.github/pr-screenshots/tob-multi-user/06-mobile-selected-again.png b/.github/pr-screenshots/tob-multi-user/06-mobile-selected-again.png new file mode 100644 index 0000000000..8de8221ac3 Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/06-mobile-selected-again.png differ diff --git a/.github/pr-screenshots/tob-multi-user/07-restart-saved.png b/.github/pr-screenshots/tob-multi-user/07-restart-saved.png new file mode 100644 index 0000000000..d8486b9e7b Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/07-restart-saved.png differ diff --git a/.github/pr-screenshots/tob-multi-user/08-refreshed-user.png b/.github/pr-screenshots/tob-multi-user/08-refreshed-user.png new file mode 100644 index 0000000000..9b6e1864d5 Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/08-refreshed-user.png differ diff --git a/.github/pr-screenshots/tob-multi-user/09-restart-selected-workspace.png b/.github/pr-screenshots/tob-multi-user/09-restart-selected-workspace.png new file mode 100644 index 0000000000..280d766426 Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/09-restart-selected-workspace.png differ diff --git a/.github/pr-screenshots/tob-multi-user/10-signed-out.png b/.github/pr-screenshots/tob-multi-user/10-signed-out.png new file mode 100644 index 0000000000..3f2b96dca3 Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/10-signed-out.png differ diff --git a/.github/pr-screenshots/tob-multi-user/README.md b/.github/pr-screenshots/tob-multi-user/README.md new file mode 100644 index 0000000000..eea9c47e8f --- /dev/null +++ b/.github/pr-screenshots/tob-multi-user/README.md @@ -0,0 +1,20 @@ +# Ordinary-user multi-workspace UAT — 2026-10-18 JST + +Native runtime `9f71dd3d9` (product source `00d9bcc6c`), compatible signed native build `494a20f1e`. Test driver checkpoints used `079832999`; only the test driver/declaration changed after the runtime freeze. Service runtime `c4c8aa44fd86dcd53650440a8350442c20420938`, Worker version `cc848bdb-d7cb-44cf-bbea-be1df39d11dc`, D1 schema 4. + +Sole BotHarness e2e iPhone 17 Pro / iOS 26 Simulator, English/light, screenshots 402×874. No native rebuild, phone action, Prod or merge. The existing trusted UAT configuration was retained. + +## Passed path + +1. Dedicated verified ordinary-user session injected through the development-only driver, then cold restart. Check session verified the full signed identity and replayed the server-owned default workspace. Status is Signed in, without an administrator label. +2. Workspaces listed the same default and second workspace as independent CLI A. The actual mobile UI created TOB Mobile collaboration, switched to My workspace and back. Formal CLI A listed and selected that exact organization; A had three organizations, B only its own one. +3. Cold restart retained the selected organization and saved session. Actual Refresh session rotated credentials and revalidated user role. The same selected organization was restored. +4. Actual Sign out revoked only the phone session. Server session status became inactive, latest phone refresh was rejected, app persisted/in-memory credentials were absent and trusted configuration remained. Independent A and B CLI sessions still worked. + +## Evidence limits and retained failures + +These recordings use API-prepared synthetic authentication; they do not prove a new Hosted AuthKit/PKCE or email-delivery flow. Previous real Hosted AuthKit acceptance belongs to #2103. Owner/member downgrade coverage belongs to #2121; this run adds ordinary-user/default/multiple-workspace coverage. Channels, invitations, Agents and cross-Host transport are not implemented by this slice. + +The initial service/CLI run had a network interruption at one denial assertion; a bounded repeat with the same identities/keys passed. Initial phone fixture preparation required handling WorkOS organization selection for a multi-org user; the test-only helper now selects an actual returned membership, and other challenges fail. Two CI failures (release-fragment metadata and the driver type declaration) were fixed and are preserved in run history. A driver log previously hard-coded verifiedAdmin:true; it now reports the actual verified role and false for this user. + +`workspaces.mp4` is 277.625 seconds; `session-recovery.mp4` is 106.323 seconds. Both are original continuous recordings with idle/tool pauses. Contact sheets are sampled previews, not additional executions. No credentials were recorded. Synthetic users and four workspaces remain for subsequent goal slices; the phone is signed out. No Human visual acceptance or physical-device qualification is claimed. diff --git a/.github/pr-screenshots/tob-multi-user/recovery-contact-sheet.png b/.github/pr-screenshots/tob-multi-user/recovery-contact-sheet.png new file mode 100644 index 0000000000..d451c5e666 Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/recovery-contact-sheet.png differ diff --git a/.github/pr-screenshots/tob-multi-user/results.json b/.github/pr-screenshots/tob-multi-user/results.json new file mode 100644 index 0000000000..ca705e18b6 --- /dev/null +++ b/.github/pr-screenshots/tob-multi-user/results.json @@ -0,0 +1,30 @@ +{ + "date": "2026-10-18", + "environment": "UAT", + "runtime": "9f71dd3d9", + "service": "c4c8aa44fd86dcd53650440a8350442c20420938", + "passed": [ + "ordinary-user-admission", + "default-replay", + "mobile-create-third-org", + "mobile-default-to-third-switch", + "independent-cli-exact-org-agreement", + "cold-restart", + "refresh-rotation", + "selected-org-retained", + "phone-remote-logout", + "phone-refresh-rejected", + "local-session-cleared", + "independent-cli-sessions-retained" + ], + "not_claimed": [ + "new-hosted-authkit", + "physical-device", + "channels", + "invitations", + "cross-host", + "human-acceptance", + "merge", + "production" + ] +} diff --git a/.github/pr-screenshots/tob-multi-user/session-recovery.mp4 b/.github/pr-screenshots/tob-multi-user/session-recovery.mp4 new file mode 100644 index 0000000000..847e5603bb Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/session-recovery.mp4 differ diff --git a/.github/pr-screenshots/tob-multi-user/workspaces-contact-sheet.png b/.github/pr-screenshots/tob-multi-user/workspaces-contact-sheet.png new file mode 100644 index 0000000000..7b2f2575bc Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/workspaces-contact-sheet.png differ diff --git a/.github/pr-screenshots/tob-multi-user/workspaces.mp4 b/.github/pr-screenshots/tob-multi-user/workspaces.mp4 new file mode 100644 index 0000000000..e1e003ad4b Binary files /dev/null and b/.github/pr-screenshots/tob-multi-user/workspaces.mp4 differ diff --git a/.github/pr-screenshots/tob-org-invitations/README.md b/.github/pr-screenshots/tob-org-invitations/README.md new file mode 100644 index 0000000000..fa57bb83ab --- /dev/null +++ b/.github/pr-screenshots/tob-org-invitations/README.md @@ -0,0 +1,31 @@ +# Organization invitations — native UAT evidence + +Runtime: `acfbc581b805a0a6b47687b7f5c23c2ca363cfcf`; signed compatible iOS development build: `494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b`. Shared Simulator, iOS 26, English, 402 × 874 logical pixels. No native-input change. Service runtime `b6b717d044ff4a787de287c31d2029025bbbb7f9`, Worker version `2722f0bc-3ee0-4214-9917-116bcb9497bd`, D1/Org/Channel schema 4/4/1. All operations used UAT. Source CI: [39080432282](https://github.com/BotHarness/DeepSeekBot/actions/runs/39080432282). + +## Observed behavior + +- Synthetic ordinary A selected its collaboration workspace, invited synthetic B through the phone, and saw Pending/member. B's independent phone session opened its inbox, accepted and selected that same workspace; four channel IDs matched the independent formal CLI. +- B could not see the seven pre-join messages in `mobile-test`. It sent `B accepted on phone and can collaborate` as message 8; both B and owner CLI read exactly one matching message with B's actual author ID. +- The real service rejected B's attempts to create a channel, issue an invitation and edit the organization. The phone offered channel reading/sending but omitted owner invitation and save controls. +- A created a separate invitation to its default workspace and revoked it from the phone. B's CLI could not accept that invitation or select that workspace. No membership was granted. +- B refreshed the phone session, cold-restarted and verified the same selected organization/member role. Three independent phone test sessions (A, B, A) signed out through the UI; the latest saved refresh token was rejected remotely, the local session was absent and every pre-existing active session remained active. A/B independent CLI sessions were preserved. +- Six owner-form size/theme combinations preserved the exact email draft and input focus. Maximum-size Invite remained hittable above the actual keyboard (button bottom ~454, keyboard top ~573; visible keyboard container starts ~557), and a real submit succeeded. Maximum-size revoke was reached by scrolling and operated. Six inbox size/theme captures show reflow; these do not prove screen-reader usability or every list action at every size. + +## Captures + +`owner-form-light` / `owner-created`: first A invitation. +`member-inbox` → `member-four-channels` → `member-no-prejoin-history` → `member-message-confirmed`: B acceptance and text. +`member-restart-role` / `member-signed-out`: restored member selection and logout. +`form-*` / `inbox-*`: default, intermediate and maximum Dynamic Type × light/dark. +`maximum-revoke-reachable` / `maximum-revoked`: action reachability and revoked result. +Videos retain real steps and waits; reviewer copies are compressed to 402px / 12fps without audio. They use synthetic `example.test` users, no credentials or invitation tokens. + +Before the new screen existed, the [base workspace entry](../tob-channel-http/01-workspace-entry.png) exposed cloud channels but no invitation entry. That is a historical entry-point comparison from runtime `7ceab0d27`, not a claim that the invitation screen existed on the base. Current owner/member captures use the same viewport/theme/locale, with role differences explicitly identified. + +## First failures and limits + +The driver initially waited for “Invitation sent.” instead of actual “Invitation created.”, used an unmatched Message selector, requested in-app Back for a modal that closes by swipe, and checkpointed before refresh finished (`SESSION_BUSY`). The revocation assertion initially expected the wrong public refusal code; actual `INVITATION_NOT_ACCEPTABLE` was independently verified. These harness failures were corrected and checks repeated; no product source changed during the native window. The first message readback failed before text was filled; the later confirmed screenshot/readback is the final proof. Recordings preserve those waits/failures rather than disguising them as a continuous first-pass success. + +No actual email delivery to a human mailbox, new Hosted AuthKit login, Android, physical phone, Human QA, screen-reader or non-Latin IME pass is claimed. Existing verified synthetic users were authenticated through the UAT-only harness and still passed normal server verification. Native uncertain-response/restart issuance was not fault-injected; source/workerd tests cover stable operation recovery. Direct channel guests, Agents, WebSocket, identity-event revocation and two-Host communication are later slices. No Prod changes or merge. + +After verification, light/large were restored, the app/driver/owned Metro stopped and the revoked phone fixture removed. Existing app data, Keychain, independent CLI fixtures, other device lanes and Hosts were preserved. diff --git a/.github/pr-screenshots/tob-org-invitations/form-appearance-checks.json b/.github/pr-screenshots/tob-org-invitations/form-appearance-checks.json new file mode 100644 index 0000000000..6b4ee7da53 --- /dev/null +++ b/.github/pr-screenshots/tob-org-invitations/form-appearance-checks.json @@ -0,0 +1,38 @@ +[ + { + "size": "large", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "large", + "theme": "dark", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-medium", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-medium", + "theme": "dark", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "light", + "draftPreserved": true, + "focused": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "dark", + "draftPreserved": true, + "focused": true + } +] diff --git a/.github/pr-screenshots/tob-org-invitations/form-default-dark.png b/.github/pr-screenshots/tob-org-invitations/form-default-dark.png new file mode 100644 index 0000000000..eda92dcc44 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/form-default-dark.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/form-default-light.png b/.github/pr-screenshots/tob-org-invitations/form-default-light.png new file mode 100644 index 0000000000..1158bd8f35 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/form-default-light.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/form-intermediate-dark.png b/.github/pr-screenshots/tob-org-invitations/form-intermediate-dark.png new file mode 100644 index 0000000000..03d4281557 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/form-intermediate-dark.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/form-intermediate-light.png b/.github/pr-screenshots/tob-org-invitations/form-intermediate-light.png new file mode 100644 index 0000000000..43c8e36366 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/form-intermediate-light.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/form-maximum-dark.png b/.github/pr-screenshots/tob-org-invitations/form-maximum-dark.png new file mode 100644 index 0000000000..54777a8eb6 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/form-maximum-dark.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/form-maximum-light.png b/.github/pr-screenshots/tob-org-invitations/form-maximum-light.png new file mode 100644 index 0000000000..390403dfc1 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/form-maximum-light.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/inbox-appearance-checks.json b/.github/pr-screenshots/tob-org-invitations/inbox-appearance-checks.json new file mode 100644 index 0000000000..425f9443be --- /dev/null +++ b/.github/pr-screenshots/tob-org-invitations/inbox-appearance-checks.json @@ -0,0 +1,32 @@ +[ + { + "size": "large", + "theme": "light", + "acceptedInvitationVisible": true + }, + { + "size": "large", + "theme": "dark", + "acceptedInvitationVisible": true + }, + { + "size": "accessibility-medium", + "theme": "light", + "acceptedInvitationVisible": true + }, + { + "size": "accessibility-medium", + "theme": "dark", + "acceptedInvitationVisible": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "light", + "acceptedInvitationVisible": true + }, + { + "size": "accessibility-extra-extra-extra-large", + "theme": "dark", + "acceptedInvitationVisible": true + } +] diff --git a/.github/pr-screenshots/tob-org-invitations/inbox-default-dark.png b/.github/pr-screenshots/tob-org-invitations/inbox-default-dark.png new file mode 100644 index 0000000000..7a62fcdb52 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/inbox-default-dark.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/inbox-default-light.png b/.github/pr-screenshots/tob-org-invitations/inbox-default-light.png new file mode 100644 index 0000000000..c787200f8b Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/inbox-default-light.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/inbox-intermediate-dark.png b/.github/pr-screenshots/tob-org-invitations/inbox-intermediate-dark.png new file mode 100644 index 0000000000..16d0b36b4a Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/inbox-intermediate-dark.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/inbox-intermediate-light.png b/.github/pr-screenshots/tob-org-invitations/inbox-intermediate-light.png new file mode 100644 index 0000000000..904b5f7a26 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/inbox-intermediate-light.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/inbox-maximum-dark.png b/.github/pr-screenshots/tob-org-invitations/inbox-maximum-dark.png new file mode 100644 index 0000000000..48843cffce Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/inbox-maximum-dark.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/inbox-maximum-light.png b/.github/pr-screenshots/tob-org-invitations/inbox-maximum-light.png new file mode 100644 index 0000000000..68dc16ed13 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/inbox-maximum-light.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/maximum-revoke-reachable.png b/.github/pr-screenshots/tob-org-invitations/maximum-revoke-reachable.png new file mode 100644 index 0000000000..621c10a97e Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/maximum-revoke-reachable.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/maximum-revoked.png b/.github/pr-screenshots/tob-org-invitations/maximum-revoked.png new file mode 100644 index 0000000000..bc45c26bc5 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/maximum-revoked.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/member-accept.mp4 b/.github/pr-screenshots/tob-org-invitations/member-accept.mp4 new file mode 100644 index 0000000000..7825203a72 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/member-accept.mp4 differ diff --git a/.github/pr-screenshots/tob-org-invitations/member-four-channels.png b/.github/pr-screenshots/tob-org-invitations/member-four-channels.png new file mode 100644 index 0000000000..df4cc30d3f Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/member-four-channels.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/member-inbox.png b/.github/pr-screenshots/tob-org-invitations/member-inbox.png new file mode 100644 index 0000000000..a45d682575 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/member-inbox.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/member-message-confirmed.png b/.github/pr-screenshots/tob-org-invitations/member-message-confirmed.png new file mode 100644 index 0000000000..69a9c12734 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/member-message-confirmed.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/member-no-prejoin-history.png b/.github/pr-screenshots/tob-org-invitations/member-no-prejoin-history.png new file mode 100644 index 0000000000..b9b3bffcb4 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/member-no-prejoin-history.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/member-restart-role.png b/.github/pr-screenshots/tob-org-invitations/member-restart-role.png new file mode 100644 index 0000000000..f1c3fff2d7 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/member-restart-role.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/member-signed-out.png b/.github/pr-screenshots/tob-org-invitations/member-signed-out.png new file mode 100644 index 0000000000..427c35b561 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/member-signed-out.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/mobile-invitation-result.json b/.github/pr-screenshots/tob-org-invitations/mobile-invitation-result.json new file mode 100644 index 0000000000..3901e187fa --- /dev/null +++ b/.github/pr-screenshots/tob-org-invitations/mobile-invitation-result.json @@ -0,0 +1,8 @@ +{ + "phoneInviteAccepted": true, + "independentCliSameOrg": true, + "memberChannelCount": 4, + "preJoinHistoryHidden": true, + "memberCannotCreateInviteOrEdit": true, + "phoneMemberMessageVisibleToOwner": true +} diff --git a/.github/pr-screenshots/tob-org-invitations/mobile-revoke-result.json b/.github/pr-screenshots/tob-org-invitations/mobile-revoke-result.json new file mode 100644 index 0000000000..3a015dfb1a --- /dev/null +++ b/.github/pr-screenshots/tob-org-invitations/mobile-revoke-result.json @@ -0,0 +1,6 @@ +{ + "phoneOwnerRevokeConfirmed": true, + "revokedRecipientCannotAccept": true, + "noMembershipGranted": true, + "ownerCliSelectionRestored": true +} diff --git a/.github/pr-screenshots/tob-org-invitations/owner-created.png b/.github/pr-screenshots/tob-org-invitations/owner-created.png new file mode 100644 index 0000000000..2819b80716 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/owner-created.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/owner-form-light.png b/.github/pr-screenshots/tob-org-invitations/owner-form-light.png new file mode 100644 index 0000000000..38e1226fcd Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/owner-form-light.png differ diff --git a/.github/pr-screenshots/tob-org-invitations/owner-invite.mp4 b/.github/pr-screenshots/tob-org-invitations/owner-invite.mp4 new file mode 100644 index 0000000000..c207a76898 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/owner-invite.mp4 differ diff --git a/.github/pr-screenshots/tob-org-invitations/owner-size-revoke.mp4 b/.github/pr-screenshots/tob-org-invitations/owner-size-revoke.mp4 new file mode 100644 index 0000000000..5d8564dd74 Binary files /dev/null and b/.github/pr-screenshots/tob-org-invitations/owner-size-revoke.mp4 differ diff --git a/.github/pr-screenshots/tob-t1-organizations/00-before-cloud-entry.png b/.github/pr-screenshots/tob-t1-organizations/00-before-cloud-entry.png new file mode 100644 index 0000000000..c91e598f68 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/00-before-cloud-entry.png differ diff --git a/.github/pr-screenshots/tob-t1-organizations/01-cloud-entry.png b/.github/pr-screenshots/tob-t1-organizations/01-cloud-entry.png new file mode 100644 index 0000000000..b40c2e46a5 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/01-cloud-entry.png differ diff --git a/.github/pr-screenshots/tob-t1-organizations/02-created-owner.png b/.github/pr-screenshots/tob-t1-organizations/02-created-owner.png new file mode 100644 index 0000000000..8a68d2ca96 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/02-created-owner.png differ diff --git a/.github/pr-screenshots/tob-t1-organizations/03-owner-saved.png b/.github/pr-screenshots/tob-t1-organizations/03-owner-saved.png new file mode 100644 index 0000000000..2302ed9cda Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/03-owner-saved.png differ diff --git a/.github/pr-screenshots/tob-t1-organizations/04-member-write-denied.png b/.github/pr-screenshots/tob-t1-organizations/04-member-write-denied.png new file mode 100644 index 0000000000..44130860e9 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/04-member-write-denied.png differ diff --git a/.github/pr-screenshots/tob-t1-organizations/05-member-readonly.png b/.github/pr-screenshots/tob-t1-organizations/05-member-readonly.png new file mode 100644 index 0000000000..7fcd1a4b23 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/05-member-readonly.png differ diff --git a/.github/pr-screenshots/tob-t1-organizations/06-restart-owner.png b/.github/pr-screenshots/tob-t1-organizations/06-restart-owner.png new file mode 100644 index 0000000000..5404eb5cc3 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/06-restart-owner.png differ diff --git a/.github/pr-screenshots/tob-t1-organizations/07-member-fixed.png b/.github/pr-screenshots/tob-t1-organizations/07-member-fixed.png new file mode 100644 index 0000000000..bd40acd890 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/07-member-fixed.png differ diff --git a/.github/pr-screenshots/tob-t1-organizations/08-owner-restored.png b/.github/pr-screenshots/tob-t1-organizations/08-owner-restored.png new file mode 100644 index 0000000000..be842d14a2 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/08-owner-restored.png differ diff --git a/.github/pr-screenshots/tob-t1-organizations/09-signed-out.png b/.github/pr-screenshots/tob-t1-organizations/09-signed-out.png new file mode 100644 index 0000000000..57fa9c9cb3 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/09-signed-out.png differ diff --git a/.github/pr-screenshots/tob-t1-organizations/README.md b/.github/pr-screenshots/tob-t1-organizations/README.md new file mode 100644 index 0000000000..c10487e5b8 --- /dev/null +++ b/.github/pr-screenshots/tob-t1-organizations/README.md @@ -0,0 +1,41 @@ +# Mobile → CLI organization acceptance (UAT) + +2026-10-18 JST · DeepSeekBot #2120 / Draft #2121 · TOB T1 #2 / Draft #17. + +## Exact source and scope + +- Create/owner-save runtime: `494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b`. +- Final permission/reselection/restart/logout runtime: `1b39324c5034eea2741abed62d579cd1044f2f86`. +- Signed native build source: `494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b`; SDK58, iOS26 Simulator. Final change is JS only. Normal local Simulator ad-hoc signing; no phone or Prod build. +- Real UAT Worker: `e5bc56298c2f63aa457ba39a1ce9ad45e2270824`; deployed version `d492f524-3489-4f97-b300-ec1e8671752e`. Service review head `fe5a8cb` adds two passing tests only. +- English / light / default text, 402 × 874 screenshots. API-prepared independent UAT session; **not a new Hosted AuthKit browser proof**. The preceding real email/PKCE run is documented separately in `../tob-t1-uat/hosted-email/`. + +## Observed path + +1. Phone reads the retained deployer-verified configuration, loads the independent test session from SecureStore and verifies the initialized administrator through the real UAT service. +2. On the actual **Cloud workspaces** screen, create **TOB Mobile UAT**. WorkOS organization + explicit owner membership, D1 mapping/creation receipt and Org DO settings are exercised through the public API. App selects the returned organization using WorkOS token refresh. +3. Phone saves `Created on mobile, read by the CLI.`. Independent formal CLI `org list`, `org use`, `org show` return the **same exact organization ID**, description, version **2** and owner role. Tokens remain private and separate. +4. Control plane changes only this new organization's membership owner → member. An already-issued owner credential receives HTTP **403 ORGANIZATION_OWNER_REQUIRED** on PATCH. CLI reads member with unchanged description/version. The actual phone's stale owner UI also receives the refusal; cached UI does not grant permission. +5. Initial native inspection found stale unsaved text and an old list role after reselecting. Fixed at `1b39324c5`: readonly content uses the verified server description, draft binding includes role, and selecting clears the draft and reloads the list. The repeated native scenario shows Member in both locations, unchanged original content and no save action. +6. Restore the test membership to active owner. Control-plane readback, CLI selection/read and phone reselection all agree. The one test organization remains for review; no second organization was created. +7. Cold restart retains credentials and selected organization but first shows **Saved session · Check to verify**. Check session restores the same organization and owner. No cached permission is presented as verified before that check. +8. Phone logout clears the session and retains public configuration. Independent WorkOS readback confirms only that test session revoked; its latest refresh token returns `invalid_grant`. Existing CLI session remains active and `org show` still returns the same owner organization/version. Revoked mobile credentials and stale test token were removed locally. +9. `allowSignUp=false`, `isMagicAuthEnabled=false` read back. Simulator driver and this task's Metro stopped; no global language preference, Host, physical phone, Prod or merge changed. + +## Media + +- `00-before-cloud-entry.png`: real prior login-only entry at runtime `216963322`, same Simulator/size/theme/locale; no workspace action. This is historical baseline evidence, not a rerun of main. +- `01`–`04`: new entry, actual create, owner save, old-owner write refusal at `494a20f1e`. +- `05-member-readonly.png`: **first failure**, unsaved local draft and stale list role; intentionally labeled as before-fix evidence, not a pass. +- `06`–`09`: final-code cold restart owner, corrected member readonly, restored owner, signed out. +- `organization-create.mp4`: 72-second real create/save path on `494a20f1e`. +- `organization-permissions-fixed.mp4`: 50-second stale-owner rejection → reload → corrected member view on `1b39324c5`. +- Contact sheets: inspected 19/17 cells from 48 sampled frames each. Recordings exclude credentials and operator control-plane pages. Both videos and all published screenshots were inspected. + +## Failed attempts and limits + +The initial unsigned Simulator build produced a Keychain entitlement error; rebuilt with normal local ad-hoc signing and reinstalled without erasing data. SecureStore load/write and logout then passed. One text replacement opened the floating development menu; that failed input was not counted as a product or authorization pass. The repeated recording uses a focused text append and verifies the actual entered draft. + +Automatic approval review rejected two optional extensions: creating a second persistent organization and deactivating the test membership. Neither action executed, and neither was retried through another route. Real UAT switching here proves unscoped → the same phone-created organization and reselection; switching between two organizations and inactive-member live rejection remain unverified. Local workerd covers scope mismatch, member/inactive/unknown/multiple-role refusals, provider outage, concurrent creation, response loss and reconciliation; those tests do not substitute for real cloud fault injection. + +Physical phone/camera, Android, VoiceOver/theme/text matrix, signed identity events/reconciliation, immediate access-JWT revocation, deployment interruption recovery and final Human acceptance remain separate T1 gates. No T2/Prod release and no merge. diff --git a/.github/pr-screenshots/tob-t1-organizations/create-contact-sheet.png b/.github/pr-screenshots/tob-t1-organizations/create-contact-sheet.png new file mode 100644 index 0000000000..f65368e5c8 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/create-contact-sheet.png differ diff --git a/.github/pr-screenshots/tob-t1-organizations/organization-create.mp4 b/.github/pr-screenshots/tob-t1-organizations/organization-create.mp4 new file mode 100644 index 0000000000..b807f55dc7 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/organization-create.mp4 differ diff --git a/.github/pr-screenshots/tob-t1-organizations/organization-permissions-fixed.mp4 b/.github/pr-screenshots/tob-t1-organizations/organization-permissions-fixed.mp4 new file mode 100644 index 0000000000..3c5701b0df Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/organization-permissions-fixed.mp4 differ diff --git a/.github/pr-screenshots/tob-t1-organizations/permissions-contact-sheet.png b/.github/pr-screenshots/tob-t1-organizations/permissions-contact-sheet.png new file mode 100644 index 0000000000..5f3972540a Binary files /dev/null and b/.github/pr-screenshots/tob-t1-organizations/permissions-contact-sheet.png differ diff --git a/.github/pr-screenshots/tob-t1-organizations/results.json b/.github/pr-screenshots/tob-t1-organizations/results.json new file mode 100644 index 0000000000..4d4449ee40 --- /dev/null +++ b/.github/pr-screenshots/tob-t1-organizations/results.json @@ -0,0 +1,26 @@ +{ + "environment": "uat", + "createRuntime": "494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b", + "finalRuntime": "1b39324c5034eea2741abed62d579cd1044f2f86", + "serviceRuntime": "e5bc56298c2f63aa457ba39a1ce9ad45e2270824", + "mobileCreated": true, + "cliExactOrganizationMatch": true, + "cliSelectedSameOrganization": true, + "ownerSaveVersion": 2, + "staleOwnerWriteStatus": 403, + "denialCode": "ORGANIZATION_OWNER_REQUIRED", + "memberReadsUnchangedData": true, + "readonlyDraftAndListRegressionFixed": true, + "restoredActiveOwner": true, + "coldRestartRevalidatedSelection": true, + "mobileSessionRevoked": true, + "latestRefreshRejected": true, + "independentCliStillAdmitted": true, + "allowSignUp": false, + "isMagicAuthEnabled": false, + "newHostedBrowserProof": false, + "secondOrganizationCreated": false, + "liveInactiveMembershipTest": "not_executed_approval_review_rejected", + "prodChanged": false, + "merged": false +} diff --git a/.github/pr-screenshots/tob-t1-uat/01-entry.png b/.github/pr-screenshots/tob-t1-uat/01-entry.png new file mode 100644 index 0000000000..2b9e8eb8f6 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/01-entry.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/02-cloud-empty.png b/.github/pr-screenshots/tob-t1-uat/02-cloud-empty.png new file mode 100644 index 0000000000..7a98f9f3ae Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/02-cloud-empty.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/02-trusted-import.mp4 b/.github/pr-screenshots/tob-t1-uat/02-trusted-import.mp4 new file mode 100644 index 0000000000..39967b7d2d Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/02-trusted-import.mp4 differ diff --git a/.github/pr-screenshots/tob-t1-uat/03-invalid-config.png b/.github/pr-screenshots/tob-t1-uat/03-invalid-config.png new file mode 100644 index 0000000000..ea51665144 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/03-invalid-config.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/04-trust-review.png b/.github/pr-screenshots/tob-t1-uat/04-trust-review.png new file mode 100644 index 0000000000..72623189ce Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/04-trust-review.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/05-imported-signed-out.png b/.github/pr-screenshots/tob-t1-uat/05-imported-signed-out.png new file mode 100644 index 0000000000..311a484af4 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/05-imported-signed-out.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/README.md b/.github/pr-screenshots/tob-t1-uat/README.md new file mode 100644 index 0000000000..b1fb7ffdb9 --- /dev/null +++ b/.github/pr-screenshots/tob-t1-uat/README.md @@ -0,0 +1,26 @@ +# TOB T1 native UAT evidence + +Captured on 2026-10-18 (JST), existing iPhone 17 Pro / iOS 26 Simulator, English/default text/light mode. Native screenshot size: 402 × 874. The Expo development overlay is visible. + +- Runtime JavaScript: `216963322c70c7ea009392da66e9a0e1f4327727`. +- Native build source: `a0b2919072af8fee62d8bb5fbb402fc52fb0d852`; subsequent changes only affect JavaScript and documentation. +- UAT service: `1ad3e6605a02965b3f9079f302ced02ca4a8f4c6`. +- Native executable SHA-256: `9afe634f14300fedd692f455eb2feaacdf07ba8d89e1777f5a0999a2f1afd753`. + +## Observed + +| Check | Result | +| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| Unpaired entry opens Cloud services without a Host | Pass | +| An ordinary URL is rejected as configuration | Pass | +| Public JSON recovers from the invalid input | Pass; the automation driver initially read the long text before entry finished; complete input and successful parsing were subsequently observed | +| Trust review displays the verified UAT server/instance before import | Pass | +| Explicit import reaches Configuration imported / Signed out | Pass | +| System WorkOS sign-in browser opens | Pass; recording stopped before sign-in | +| User authentication, callback, refresh, cold restart and logout isolation | Pending at initial capture; see subsequent unattended session report below | + +The screenshots compare states within the same revision, not an older-code baseline. `02-trusted-import.mp4` records the trust confirmation → imported result. Authentication forms, account details, codes and tokens are excluded. These assets do not qualify physical QR scanning, Android, dark/large-text/VoiceOver, or the rest of T1. The existing Simulator system CJK-font failure is a separate known environment limitation; no system font repair was attempted. + +## Subsequent unattended session run + +[Native session report and recording](unattended/README.md): real API authentication, native identity check, refresh rotation, cold restart and own-session logout/CLI isolation passed without Human login. Successful Hosted AuthKit/PKCE browser return remains unqualified. diff --git a/.github/pr-screenshots/tob-t1-uat/browser/01-local-signed-out.png b/.github/pr-screenshots/tob-t1-uat/browser/01-local-signed-out.png new file mode 100644 index 0000000000..1acf65c541 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/browser/01-local-signed-out.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/browser/02-emulator-browser.png b/.github/pr-screenshots/tob-t1-uat/browser/02-emulator-browser.png new file mode 100644 index 0000000000..c4be545a6e Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/browser/02-emulator-browser.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/browser/03-returned-signed-in.png b/.github/pr-screenshots/tob-t1-uat/browser/03-returned-signed-in.png new file mode 100644 index 0000000000..fa3e93466f Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/browser/03-returned-signed-in.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/browser/04-wrong-state.png b/.github/pr-screenshots/tob-t1-uat/browser/04-wrong-state.png new file mode 100644 index 0000000000..1f95f9f7d7 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/browser/04-wrong-state.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/browser/05-wrong-verifier.png b/.github/pr-screenshots/tob-t1-uat/browser/05-wrong-verifier.png new file mode 100644 index 0000000000..3e075ededa Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/browser/05-wrong-verifier.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/browser/06-real-uat-restored.png b/.github/pr-screenshots/tob-t1-uat/browser/06-real-uat-restored.png new file mode 100644 index 0000000000..f4f466e2f4 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/browser/06-real-uat-restored.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/browser/README.md b/.github/pr-screenshots/tob-t1-uat/browser/README.md new file mode 100644 index 0000000000..2425f199a3 --- /dev/null +++ b/.github/pr-screenshots/tob-t1-uat/browser/README.md @@ -0,0 +1,27 @@ +# Native AuthKit browser acceptance — 2026-10-18 JST + +## Local unattended regression: passed + +Product JS: `216963322c70c7ea009392da66e9a0e1f4327727`; retained iOS native source: `a0b2919072af8fee62d8bb5fbb402fc52fb0d852`; driver: `b341c6454`. The driver changes test tooling only. Simulator: iPhone 17 Pro / iOS 26, 402 × 874, light/default text. WorkOS Emulate **0.15.0**, bound to loopback; no real identity or cloud request in this layer. + +| Path | Observation | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Normal login | Actual Expo system browser displayed WORKOS EMULATE, then returned to the same App. Normal CloudClient state check and code exchange succeeded using native Crypto's S256 verifier, without client secret. | +| Replay | Immediate second exchange of the same authorization code returned HTTP 400 / invalid_grant. | +| Wrong state | Native INVALID_CALLBACK, no token request and no session. | +| Wrong verifier | Emulator rejected exchange with HTTP 400; native LOGIN_FAILED and no session. | +| Isolation | Fixture visibly named LOCAL EMULATOR - not UAT; storage only in memory. Original runtime/config restored afterward, real UAT still signed out. | + +The 68-second recording includes keyboard occlusion, dismissal and successful return, followed by restoring/resetting the local fixture at the end; that last state is **not a logout proof**. Screenshots and the 24-cell contact sheet were inspected; all form data in this recording are fictional. No real authentication-form footage is published. + +The official emulator rejects our hostless custom callback spelling. The test-only loopback adapter maps an HTTP callback returned by the emulator to the unchanged native URI. It does not change the app's callback checks. This proves native browser return and client PKCE/state behavior against the emulator, **not** live WorkOS callback registration or actual TOB admission. The fixture identity response is local, albeit backed by a verified emulator JWT signature. Existing real-UAT session-lifecycle evidence remains a distinct layer. + +## Live unattended smoke attempt: not passed + +A bounded real Staging attempt used the existing initialized administrator, normal Hosted AuthKit and an API-created email code. The initial native fill stopped because the six one-character inputs and invalidated accessibility refs require per-field fresh snapshots. After correcting input handling, the hosted page rejected the code as expired. Whether an API-created code can complete that pre-existing Hosted AuthKit transaction was **not established**; this is not a successful native hosted login. + +The browser transaction was canceled. Magic Auth was restored to its previous disabled value; signup remained disabled. The one-time code file was removed. No password change, new user, account-role change, Radar bypass, deployment or Prod operation occurred. The local suite follows [WorkOS testing guidance](https://workos.com/docs/authkit/testing); routine automation should not depend on live hosted-page bots. + +## T1 close gates still separate + +The successful live hosted browser gate is recorded separately when completed. T1 additionally needs the organization slice (mobile create/list/switch and independent CLI readback), owner/member and no-membership denials, idempotent WorkOS/D1/Org DO creation/recovery, signed identity events and reconciliation/revocation windows, and the remaining deployment/import/native/Human-QA matrix. Physical QR capture, Android and accessibility/theme qualification have not been demonstrated by this Simulator run. Neither this report nor green CI closes T1 or authorizes T2/Prod. diff --git a/.github/pr-screenshots/tob-t1-uat/browser/browser-success.mp4 b/.github/pr-screenshots/tob-t1-uat/browser/browser-success.mp4 new file mode 100644 index 0000000000..4458550fa6 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/browser/browser-success.mp4 differ diff --git a/.github/pr-screenshots/tob-t1-uat/browser/contact-sheet.png b/.github/pr-screenshots/tob-t1-uat/browser/contact-sheet.png new file mode 100644 index 0000000000..0cee9c1507 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/browser/contact-sheet.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/browser/success.json b/.github/pr-screenshots/tob-t1-uat/browser/success.json new file mode 100644 index 0000000000..e42c03a9d4 --- /dev/null +++ b/.github/pr-screenshots/tob-t1-uat/browser/success.json @@ -0,0 +1,11 @@ +{ + "scenario": "success", + "authorizeS256": true, + "nativeCallbackRedirect": true, + "tokenRequests": 1, + "publicClient": true, + "verifierMatchesChallenge": true, + "exchangeStatus": 200, + "replayedCodeRejected": true, + "fixtureIdentityVerified": true +} diff --git a/.github/pr-screenshots/tob-t1-uat/browser/wrong-state.json b/.github/pr-screenshots/tob-t1-uat/browser/wrong-state.json new file mode 100644 index 0000000000..fa40f0064c --- /dev/null +++ b/.github/pr-screenshots/tob-t1-uat/browser/wrong-state.json @@ -0,0 +1,5 @@ +{ + "scenario": "wrong-state", + "authorizeS256": true, + "nativeCallbackRedirect": true +} diff --git a/.github/pr-screenshots/tob-t1-uat/browser/wrong-verifier.json b/.github/pr-screenshots/tob-t1-uat/browser/wrong-verifier.json new file mode 100644 index 0000000000..7e8eb8041f --- /dev/null +++ b/.github/pr-screenshots/tob-t1-uat/browser/wrong-verifier.json @@ -0,0 +1,9 @@ +{ + "scenario": "wrong-verifier", + "authorizeS256": true, + "nativeCallbackRedirect": true, + "tokenRequests": 1, + "publicClient": true, + "verifierMatchesChallenge": true, + "exchangeStatus": 400 +} diff --git a/.github/pr-screenshots/tob-t1-uat/hosted-email/01-hosted-returned.png b/.github/pr-screenshots/tob-t1-uat/hosted-email/01-hosted-returned.png new file mode 100644 index 0000000000..c91e598f68 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/hosted-email/01-hosted-returned.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/hosted-email/02-refreshed.png b/.github/pr-screenshots/tob-t1-uat/hosted-email/02-refreshed.png new file mode 100644 index 0000000000..020bc88f16 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/hosted-email/02-refreshed.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/hosted-email/03-restart-unverified.png b/.github/pr-screenshots/tob-t1-uat/hosted-email/03-restart-unverified.png new file mode 100644 index 0000000000..7b698f9910 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/hosted-email/03-restart-unverified.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/hosted-email/04-restart-verified.png b/.github/pr-screenshots/tob-t1-uat/hosted-email/04-restart-verified.png new file mode 100644 index 0000000000..020bc88f16 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/hosted-email/04-restart-verified.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/hosted-email/05-logged-out.png b/.github/pr-screenshots/tob-t1-uat/hosted-email/05-logged-out.png new file mode 100644 index 0000000000..cf5222101e Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/hosted-email/05-logged-out.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/hosted-email/06-restart-signed-out.png b/.github/pr-screenshots/tob-t1-uat/hosted-email/06-restart-signed-out.png new file mode 100644 index 0000000000..fd4dc5cda9 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/hosted-email/06-restart-signed-out.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/hosted-email/README.md b/.github/pr-screenshots/tob-t1-uat/hosted-email/README.md new file mode 100644 index 0000000000..9eb1b1b8af --- /dev/null +++ b/.github/pr-screenshots/tob-t1-uat/hosted-email/README.md @@ -0,0 +1,42 @@ +# Real Hosted AuthKit email login — iOS Simulator UAT + +Verified on 2026-10-18 (Asia/Tokyo), for DeepSeekBot #2101 / PR #2103 and TOB T1 #2. + +## Identity and scope + +- Product runtime: `216963322c70c7ea009392da66e9a0e1f4327727`. +- Retained native build source: `a0b2919072af8fee62d8bb5fbb402fc52fb0d852` (SDK58, iOS26 Simulator). +- UAT service: `1ad3e6605a02965b3f9079f302ced02ca4a8f4c6`. +- App language English, light appearance, default system text, 402 × 874 captures. +- No product code, cloud deployment, Prod configuration or role change in this run. + +## What passed + +1. Started signed out with the previously imported real UAT configuration and no emulator runtime adapter. The normal App **Sign in** action opened real Hosted AuthKit with its native S256 challenge/state and registered callback. +2. Temporarily enabled only Magic Auth in the verified WorkOS staging environment; registration remained closed. The hosted page sent the email code. After an automated input attempt was rejected, the page resent it and **the Human entered the new code directly in Device Hub**. The hosted browser returned to the App through the normal PKCE/state/code-exchange implementation; no injected API session or emulator token was used for this success. +3. The App showed **Signed in · Instance administrator**. Independent real UAT `/api/me` and WorkOS session readback matched the accepted bootstrap user, admitted administrator, exact trusted configuration and a fresh session absent from the baseline. The separate CLI session remained active. +4. **Refresh session** rotated the refresh token while preserving the same WorkOS session and admitted user. +5. Cold restart retained the saved session but displayed **Saved session · Check to verify**. **Check session** restored the same admitted administrator/session. +6. **Sign out** cleared App memory/SecureStore and reported remote revocation. WorkOS readback confirmed this session inactive; its latest rotated refresh token was rejected. The baseline CLI session remained active and the formal CLI `whoami` independently succeeded. +7. A second cold restart remained **Signed out** and retained public configuration. +8. Restored Magic Auth to disabled and read back `allowSignUp=false`, `isMagicAuthEnabled=false`. Closed the recorder/driver and released the shared Simulator window. No other session was revoked. + +## Evidence + +- `01-hosted-returned.png`: the admitted state after the actual hosted browser return. +- `02-refreshed.png`: refresh complete. +- `03-restart-unverified.png`: saved credentials after cold restart, before revalidation. +- `04-restart-verified.png`: same user/session verified again. +- `05-logged-out.png`: local cleanup and remote result shown in App. +- `06-restart-signed-out.png`: persistent signed-out state. +- `hosted-session.mp4`: 92-second post-login refresh/restart/logout/restart recording. +- `contact-sheet.png`: inspected 20-cell summary from 48 sampled frames. +- `results.json`: sanitized observed results; credentials and private session IDs are excluded. + +All six screenshots were inspected. Credential entry and the browser callback URL were deliberately not recorded; the recording starts **after** successful authentication. This is observed Human-assisted real hosted acceptance, not a recording of the complete login form and not unattended hosted authentication. + +## Failures and limits + +The first local hidden-input attempt submitted six digits but Hosted AuthKit rejected the code. The initial helper did not compare every entered digit; cause is unconfirmed. A revised helper added comparison, but the Human completed the accepted retry directly, so automated hosted OTP entry remains unqualified. The Node module-format warning was unrelated to the login result. A temporary checkpoint initially compared unsorted JSON keys, and an immediate post-refresh check ran while the App was busy; stable configuration comparison and a post-completion readback resolved these diagnostic failures without changing the product. + +This supersedes the earlier real-hosted pending note in `../browser/README.md` for the successful email/PKCE path only. Google login, physical QR/camera, Android, VoiceOver/theme/text matrix and remaining native failure scenarios are still separate gates. This run does not establish immediate invalidation of already-issued access JWTs. Broader T1 organization creation/list/switch, membership/permission, retries/reconciliation/revocation and final review remain open. No merge or T2 release. diff --git a/.github/pr-screenshots/tob-t1-uat/hosted-email/contact-sheet.png b/.github/pr-screenshots/tob-t1-uat/hosted-email/contact-sheet.png new file mode 100644 index 0000000000..3ee771ae87 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/hosted-email/contact-sheet.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/hosted-email/hosted-session.mp4 b/.github/pr-screenshots/tob-t1-uat/hosted-email/hosted-session.mp4 new file mode 100644 index 0000000000..96d426bd71 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/hosted-email/hosted-session.mp4 differ diff --git a/.github/pr-screenshots/tob-t1-uat/hosted-email/results.json b/.github/pr-screenshots/tob-t1-uat/hosted-email/results.json new file mode 100644 index 0000000000..b0b9378943 --- /dev/null +++ b/.github/pr-screenshots/tob-t1-uat/hosted-email/results.json @@ -0,0 +1,23 @@ +{ + "environment": "uat", + "hostedEmailLogin": "passed-human-assisted", + "normalNativePkceCallback": true, + "emulatorUsed": false, + "sessionInjected": false, + "bootstrapUserMatches": true, + "trustedConfigMatches": true, + "freshWorkosSession": true, + "refreshRotated": true, + "sameSessionAfterRestart": true, + "restartRequiresVerification": true, + "ownSessionRevoked": true, + "latestRefreshRejected": true, + "independentCliAdmitted": true, + "localAndStoredSessionRemoved": true, + "signedOutAfterRestart": true, + "configRetained": true, + "magicAuthRestoredDisabled": true, + "registrationRemainedClosed": true, + "credentialEntryRecorded": false, + "automatedHostedOtpEntry": "not-qualified" +} diff --git a/.github/pr-screenshots/tob-t1-uat/unattended/01-native-session.mp4 b/.github/pr-screenshots/tob-t1-uat/unattended/01-native-session.mp4 new file mode 100644 index 0000000000..e9f341c432 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/unattended/01-native-session.mp4 differ diff --git a/.github/pr-screenshots/tob-t1-uat/unattended/01-saved-unverified.png b/.github/pr-screenshots/tob-t1-uat/unattended/01-saved-unverified.png new file mode 100644 index 0000000000..b4860f66c3 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/unattended/01-saved-unverified.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/unattended/02-verified-admin.png b/.github/pr-screenshots/tob-t1-uat/unattended/02-verified-admin.png new file mode 100644 index 0000000000..1f2b825943 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/unattended/02-verified-admin.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/unattended/03-refreshed-admin.png b/.github/pr-screenshots/tob-t1-uat/unattended/03-refreshed-admin.png new file mode 100644 index 0000000000..0287afae58 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/unattended/03-refreshed-admin.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/unattended/04-restart-saved.png b/.github/pr-screenshots/tob-t1-uat/unattended/04-restart-saved.png new file mode 100644 index 0000000000..a32aa5e8b2 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/unattended/04-restart-saved.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/unattended/05-restart-verified.png b/.github/pr-screenshots/tob-t1-uat/unattended/05-restart-verified.png new file mode 100644 index 0000000000..0287afae58 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/unattended/05-restart-verified.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/unattended/06-logged-out.png b/.github/pr-screenshots/tob-t1-uat/unattended/06-logged-out.png new file mode 100644 index 0000000000..107c7d72bb Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/unattended/06-logged-out.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/unattended/07-restart-signed-out.png b/.github/pr-screenshots/tob-t1-uat/unattended/07-restart-signed-out.png new file mode 100644 index 0000000000..16e766f487 Binary files /dev/null and b/.github/pr-screenshots/tob-t1-uat/unattended/07-restart-signed-out.png differ diff --git a/.github/pr-screenshots/tob-t1-uat/unattended/README.md b/.github/pr-screenshots/tob-t1-uat/unattended/README.md new file mode 100644 index 0000000000..51672d4fa7 --- /dev/null +++ b/.github/pr-screenshots/tob-t1-uat/unattended/README.md @@ -0,0 +1,34 @@ +# Unattended native UAT session verification + +2026-10-18, 04:11–04:14 JST. Existing iPhone 17 Pro / iOS 26 Simulator, English, default text, light mode, 402 × 874. No Human login was required. No production deployment or product authorization change was made. + +## What this proves + +A separate session was authenticated through real WorkOS Staging's Magic Auth API and admitted by the real TOB UAT service. A local debugger fixture wrote it through the existing native SecureStore adapter, only after matching the already-trusted public UAT config. The App was then cold-started and operated through its normal native UI. This is **API authentication + native session lifecycle**, not a successful Hosted AuthKit/PKCE browser-login test. + +| Observable behavior | Result and evidence | +| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| Real API authentication and UAT admin admission | Pass; private operator profile and accepted bootstrap identity checked; no fake JWT or server bypass | +| Saved session is not initially treated as verified identity | Pass; `01-saved-unverified.png` | +| Native Check session verifies admin through UAT | Pass; `02-verified-admin.png`; same-session checkpoint | +| Native Refresh session rotates and persists refresh token | Pass; `03-refreshed-admin.png`; checkpoint reported rotation, not just matching UI text | +| Cold restart reads saved session but requires fresh identity verification | Pass; `04-restart-saved.png` → `05-restart-verified.png`; same session, same saved refresh token | +| Native Sign out clears local session and reports remote revocation | Pass; `06-logged-out.png`; memory and SecureStore both checked | +| WorkOS revocation and session isolation | Pass; exact fixture session inactive, its latest saved refresh token returned invalid_grant, all prior active sessions retained | +| Independent formal CLI remains usable | Pass; CLI whoami still verified the UAT administrator after App logout | +| Another cold restart stays signed out and retains trusted config | Pass; `07-restart-signed-out.png` | + +The first native Check session also rotated the API-prepared token before verifying identity; the explicit Refresh session then rotated it again. Cold restart restored that latest token without unexpected rotation. Issued access JWTs were **not** claimed to be instantly invalidated by logout; the remote assertion is session revocation and refresh rejection. + +## Source and evidence boundaries + +- Product runtime JS: `216963322c70c7ea009392da66e9a0e1f4327727`, the frozen shared batch. Product app/native inputs remain identical through driver commit `c12bc7936bd015f058d09b05d4ff3481c9e608a6`. +- Retained native build source: `a0b2919072af8fee62d8bb5fbb402fc52fb0d852`; previously verified executable SHA-256 `9afe634f14300fedd692f455eb2feaacdf07ba8d89e1777f5a0999a2f1afd753`. The intervening Settings build was never installed before this run. +- UAT service: `1ad3e6605a02965b3f9079f302ced02ca4a8f4c6`. +- Driver source: `c12bc7936bd015f058d09b05d4ff3481c9e608a6`. The local driver was refined during this run for pnpm dependency resolution, Hermes asynchronous evaluation, explicit Simulator target matching and same-fixture retry. Its final signed-out check passed; 18 focused driver/client tests, mobile typecheck, targeted lint/format passed. Earlier source baseline mobile suite was 550 pass / 8 skip; this report does not relabel that as a rerun at the final head. + +`01-native-session.mp4` is a 105.9-second native recording: saved/unverified → checked → refreshed → cold restart → checked → signed out. Seven screenshots and the recording's 17-cell contact sheet were visually inspected before publication. Preparation, injection, auth forms, codes, tokens and personal account identifiers are absent. The Expo development overlay is visible. Images compare states in the same revision, not an older-code baseline. + +One private temporary session was created for this run. The existing CLI session was independent. The temporary Magic Auth setting was restored, registration stayed closed, the fixture session was revoked, and its local credential file was removed after verification. The Simulator driver/recording were closed and the shared window returned; trusted config and app data were retained. + +Still unqualified: Hosted AuthKit successful browser return/PKCE, physical-camera QR, Android, dark/large-text/VoiceOver and Human product acceptance. Earlier native browser-open/cancel checks remain separate. This evidence does not close TOB T1's remaining organization and permission slices. diff --git a/apps/mobile/README.md b/apps/mobile/README.md index 978519ca3e..51507c4df3 100644 --- a/apps/mobile/README.md +++ b/apps/mobile/README.md @@ -156,3 +156,7 @@ Use the repository's pinned Node and pnpm versions. SDK 58 targets React Native CI checks Expo Doctor, types and tests, and exports both iOS and Android bundles in a required `mobile-export` job. Exporting bundles does not compile native code: separately verify a fresh iOS build and Android Release build (including R8), then the native user journeys. Android compilation requires compile SDK 37. The web preview explicitly retains single-page output. The simulator cache uses the strict fingerprint preset so app-version changes invalidate a cached native binary; SDK 58's balanced default ignores those version fields. For retained-data acceptance, install over an existing build with the same app identity and verify paired Hosts, local appearance, collapsed sections, DM activity preferences and statistics settings after restart. The fresh-install simulator journey alone does not prove upgrade preservation. Record simulator, real-device and Human QA results separately; follow [shared device QA](../../docs/agents/device-qa.md) for scheduling and resource limits. + +### Channel Agents (UAT candidate) + +Open Cloud channels → choose an owned channel → Channel agents. Create a named Agent, then explicitly Copy credential into its private configuration file. Only message read/send is granted in this channel; no organization membership or computer execution permission. One saved handoff can be retried after restart. Remove saved credential does not revoke the Agent; Revoke agent does. Secrets are omitted from normal snapshots/logs, and sign-out removes the saved handoff. Real UAT/native evidence is still pending for this increment. diff --git a/apps/mobile/app.json b/apps/mobile/app.json index 8cbd92274a..a16daee81c 100644 --- a/apps/mobile/app.json +++ b/apps/mobile/app.json @@ -2,7 +2,7 @@ "expo": { "name": "DeepSeekBot Dev", "slug": "deepseekbot", - "scheme": ["deepseekbot-dev", "deepseekbot"], + "scheme": ["deepseekbot-dev", "deepseekbot", "ai.botharness.deepseekbot.dev"], "version": "0.0.1", "orientation": "portrait", "userInterfaceStyle": "automatic", @@ -79,7 +79,8 @@ "expo-font", "expo-image", "expo-sharing", - "expo-status-bar" + "expo-status-bar", + "expo-web-browser" ], "web": { "output": "single" diff --git a/apps/mobile/app/+native-intent.tsx b/apps/mobile/app/+native-intent.tsx new file mode 100644 index 0000000000..49bd002b13 --- /dev/null +++ b/apps/mobile/app/+native-intent.tsx @@ -0,0 +1,4 @@ +import { cloudNativeIntent } from '../src/cloud/native-intent'; +export function redirectSystemPath({ path }: { path: string; initial: boolean }) { + return cloudNativeIntent(path); +} diff --git a/apps/mobile/app/_layout.tsx b/apps/mobile/app/_layout.tsx index 2b10ff03c1..82772f7530 100644 --- a/apps/mobile/app/_layout.tsx +++ b/apps/mobile/app/_layout.tsx @@ -60,6 +60,17 @@ export default function RootLayout() { /> + + + + + (); const lastMethod = useRef('paste'); const pending = useRef(undefined); @@ -58,9 +59,13 @@ export default function PairScreen() { useFocusEffect( useCallback(() => { + setFocused(true); if (typeof params.p === 'string' && handled.current === undefined) void pair(`deepseekbot://pair?p=${params.p}`, 'deep_link'); - return () => pending.current?.abort(); + return () => { + setFocused(false); + pending.current?.abort(); + }; }, [params.p]), ); @@ -78,6 +83,7 @@ export default function PairScreen() { style={{ flex: 1, backgroundColor: theme.background }} contentContainerStyle={{ padding: 16, gap: 12 }} > +