From 0b82f88e9f2b6904f8ecf296b11d0581de4cfbb9 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Wed, 21 Oct 2026 13:42:30 -0700 Subject: [PATCH] fix(mobile): dispatch leading terminal scroll without a timer (#31472) Dispatch the leading terminal scroll immediately and coalesce subsequent movement behind the outstanding request. Preserve queue expiry, limits and ordering. Closes #30299. Adapted from #30311. Co-authored-by: Wooseong Kim --- ...chestration.workerterminaluserinput-1.json | 233 +++--- ...-gesture-input-terminal.clearbuffer-1.json | 195 +++-- ...erminal-gesture-input-terminal.send-1.json | 785 +++++++++--------- .../terminal-gesture-flush-and-clear.json | 163 ++-- .../session/mobile-session-route-helpers.ts | 1 - .../terminal-gesture-input-delivery.test.ts | 152 ++++ .../use-mobile-session-terminal-input.ts | 16 +- 7 files changed, 829 insertions(+), 716 deletions(-) create mode 100644 mobile/src/session/terminal-gesture-input-delivery.test.ts diff --git a/mobile/rpc-foundation/goldens/matrix-session.terminal-gesture-input-orchestration.workerterminaluserinput-1.json b/mobile/rpc-foundation/goldens/matrix-session.terminal-gesture-input-orchestration.workerterminaluserinput-1.json index 8c3c0c69e15..590f406c10b 100644 --- a/mobile/rpc-foundation/goldens/matrix-session.terminal-gesture-input-orchestration.workerterminaluserinput-1.json +++ b/mobile/rpc-foundation/goldens/matrix-session.terminal-gesture-input-orchestration.workerterminaluserinput-1.json @@ -145,6 +145,48 @@ } } }, + "47c387a75ffc": { + "name": "terminal.send#1", + "ordinal": 1, + "args": [ + { + "name": "method", + "value": "terminal.send" + }, + { + "name": "params", + "value": { + "client": { + "id": "device-token-1", + "type": "mobile" + }, + "enter": false, + "terminal": "terminal-1", + "text": "\u001b[<64;10;5M" + } + }, + { + "name": "options", + "value": { + "failWhenDisconnected": true + } + } + ], + "settlement": { + "status": "fulfilled", + "startedAt": 0, + "settledAt": 16, + "value": { + "id": "frame-1", + "ok": true, + "result": { + "send": { + "accepted": true + } + } + } + } + }, "60ae3b4c26a5": { "name": "orchestration.workerTerminalUserInput#1", "ordinal": 3, @@ -265,15 +307,6 @@ "ordinal": 6, "json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"terminal.clearBuffer\",\"params\":{\"terminal\":\"terminal-1\"}}" }, - "93092a2f06c5": { - "bucketTokens": 63, - "crash": { - "$rpc": "null" - }, - "inFlight": false, - "queuedBytes": "\u001b[<64;10;5M", - "queuedSequences": 1 - }, "94ce15ec36dc": { "name": "orchestration.workerTerminalUserInput#1", "ordinal": 3, @@ -383,6 +416,38 @@ } } }, + "9fa6cd0b7fa0": { + "name": "terminal.send#1", + "ordinal": 1, + "args": [ + { + "name": "method", + "value": "terminal.send" + }, + { + "name": "params", + "value": { + "client": { + "id": "device-token-1", + "type": "mobile" + }, + "enter": false, + "terminal": "terminal-1", + "text": "\u001b[<64;10;5M" + } + }, + { + "name": "options", + "value": { + "failWhenDisconnected": true + } + } + ], + "settlement": { + "status": "pending", + "startedAt": 0 + } + }, "aa1058fa6654": { "name": "orchestration.workerTerminalUserInput#1", "ordinal": 3, @@ -443,48 +508,6 @@ "startedAt": 16 } }, - "c9e4131930e5": { - "name": "terminal.send#1", - "ordinal": 1, - "args": [ - { - "name": "method", - "value": "terminal.send" - }, - { - "name": "params", - "value": { - "client": { - "id": "device-token-1", - "type": "mobile" - }, - "enter": false, - "terminal": "terminal-1", - "text": "\u001b[<64;10;5M" - } - }, - { - "name": "options", - "value": { - "failWhenDisconnected": true - } - } - ], - "settlement": { - "status": "fulfilled", - "startedAt": 16, - "settledAt": 16, - "value": { - "id": "frame-1", - "ok": true, - "result": { - "send": { - "accepted": true - } - } - } - } - }, "caa6ece1bdab": { "bucketTokens": 63, "crash": { @@ -609,38 +632,6 @@ } } } - }, - "fd81ada317ab": { - "name": "terminal.send#1", - "ordinal": 1, - "args": [ - { - "name": "method", - "value": "terminal.send" - }, - { - "name": "params", - "value": { - "client": { - "id": "device-token-1", - "type": "mobile" - }, - "enter": false, - "terminal": "terminal-1", - "text": "\u001b[<64;10;5M" - } - }, - { - "name": "options", - "value": { - "failWhenDisconnected": true - } - } - ], - "settlement": { - "status": "pending", - "startedAt": 16 - } } }, "recording": { @@ -649,20 +640,20 @@ { "id": "terminal-gesture-flush-and-clear.prelude:queued", "observation": { - "sender": [], - "payloads": [], + "sender": ["9fa6cd0b7fa0"], + "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", "gesture": "eb79a9b3682a" }, - "state": "93092a2f06c5", + "state": "caa6ece1bdab", "effects": [] } }, { "id": "terminal-gesture-flush-and-clear.prelude:flushing", "observation": { - "sender": ["fd81ada317ab"], + "sender": ["9fa6cd0b7fa0"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -675,7 +666,7 @@ { "id": "terminal-gesture-flush-and-clear.prelude:sent", "observation": { - "sender": ["c9e4131930e5", "77d8a44e0dcc"], + "sender": ["47c387a75ffc", "77d8a44e0dcc"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -688,7 +679,7 @@ { "id": "terminal-gesture-flush-and-clear.normal:reported", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc"], + "sender": ["47c387a75ffc", "94ce15ec36dc"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -701,7 +692,7 @@ { "id": "terminal-gesture-flush-and-clear.normal:clearing", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "afb61324f54a"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -715,7 +706,7 @@ { "id": "terminal-gesture-flush-and-clear.normal:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -729,7 +720,7 @@ { "id": "terminal-gesture-flush-and-clear.result-absent:reported", "observation": { - "sender": ["c9e4131930e5", "e24bc71ad7f1"], + "sender": ["47c387a75ffc", "e24bc71ad7f1"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -742,7 +733,7 @@ { "id": "terminal-gesture-flush-and-clear.result-absent:clearing", "observation": { - "sender": ["c9e4131930e5", "e24bc71ad7f1", "afb61324f54a"], + "sender": ["47c387a75ffc", "e24bc71ad7f1", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -756,7 +747,7 @@ { "id": "terminal-gesture-flush-and-clear.result-absent:cleared", "observation": { - "sender": ["c9e4131930e5", "e24bc71ad7f1", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "e24bc71ad7f1", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -770,7 +761,7 @@ { "id": "terminal-gesture-flush-and-clear.result-null:reported", "observation": { - "sender": ["c9e4131930e5", "9c7f27a40956"], + "sender": ["47c387a75ffc", "9c7f27a40956"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -783,7 +774,7 @@ { "id": "terminal-gesture-flush-and-clear.result-null:clearing", "observation": { - "sender": ["c9e4131930e5", "9c7f27a40956", "afb61324f54a"], + "sender": ["47c387a75ffc", "9c7f27a40956", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -797,7 +788,7 @@ { "id": "terminal-gesture-flush-and-clear.result-null:cleared", "observation": { - "sender": ["c9e4131930e5", "9c7f27a40956", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "9c7f27a40956", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -811,7 +802,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-ok-missing:reported", "observation": { - "sender": ["c9e4131930e5", "0bbc8e9d2e60"], + "sender": ["47c387a75ffc", "0bbc8e9d2e60"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -824,7 +815,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-ok-missing:clearing", "observation": { - "sender": ["c9e4131930e5", "0bbc8e9d2e60", "afb61324f54a"], + "sender": ["47c387a75ffc", "0bbc8e9d2e60", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -838,7 +829,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-ok-missing:cleared", "observation": { - "sender": ["c9e4131930e5", "0bbc8e9d2e60", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "0bbc8e9d2e60", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -852,7 +843,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-string-error:reported", "observation": { - "sender": ["c9e4131930e5", "41eb762c53f0"], + "sender": ["47c387a75ffc", "41eb762c53f0"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -865,7 +856,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-string-error:clearing", "observation": { - "sender": ["c9e4131930e5", "41eb762c53f0", "afb61324f54a"], + "sender": ["47c387a75ffc", "41eb762c53f0", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -879,7 +870,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-string-error:cleared", "observation": { - "sender": ["c9e4131930e5", "41eb762c53f0", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "41eb762c53f0", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -893,7 +884,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-object-error:reported", "observation": { - "sender": ["c9e4131930e5", "8412fcb9c620"], + "sender": ["47c387a75ffc", "8412fcb9c620"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -906,7 +897,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-object-error:clearing", "observation": { - "sender": ["c9e4131930e5", "8412fcb9c620", "afb61324f54a"], + "sender": ["47c387a75ffc", "8412fcb9c620", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -920,7 +911,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-object-error:cleared", "observation": { - "sender": ["c9e4131930e5", "8412fcb9c620", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "8412fcb9c620", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -934,7 +925,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused:reported", "observation": { - "sender": ["c9e4131930e5", "dfe8d1bab9c5"], + "sender": ["47c387a75ffc", "dfe8d1bab9c5"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -947,7 +938,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused:clearing", "observation": { - "sender": ["c9e4131930e5", "dfe8d1bab9c5", "afb61324f54a"], + "sender": ["47c387a75ffc", "dfe8d1bab9c5", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -961,7 +952,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused:cleared", "observation": { - "sender": ["c9e4131930e5", "dfe8d1bab9c5", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "dfe8d1bab9c5", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -975,7 +966,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused-no-message:reported", "observation": { - "sender": ["c9e4131930e5", "9850afd5b555"], + "sender": ["47c387a75ffc", "9850afd5b555"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -988,7 +979,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused-no-message:clearing", "observation": { - "sender": ["c9e4131930e5", "9850afd5b555", "afb61324f54a"], + "sender": ["47c387a75ffc", "9850afd5b555", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -1002,7 +993,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused-no-message:cleared", "observation": { - "sender": ["c9e4131930e5", "9850afd5b555", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "9850afd5b555", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -1016,7 +1007,7 @@ { "id": "terminal-gesture-flush-and-clear.method-not-found:reported", "observation": { - "sender": ["c9e4131930e5", "31a1ebf3ac68"], + "sender": ["47c387a75ffc", "31a1ebf3ac68"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -1029,7 +1020,7 @@ { "id": "terminal-gesture-flush-and-clear.method-not-found:clearing", "observation": { - "sender": ["c9e4131930e5", "31a1ebf3ac68", "afb61324f54a"], + "sender": ["47c387a75ffc", "31a1ebf3ac68", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -1043,7 +1034,7 @@ { "id": "terminal-gesture-flush-and-clear.method-not-found:cleared", "observation": { - "sender": ["c9e4131930e5", "31a1ebf3ac68", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "31a1ebf3ac68", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -1057,7 +1048,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection:reported", "observation": { - "sender": ["c9e4131930e5", "aa1058fa6654"], + "sender": ["47c387a75ffc", "aa1058fa6654"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -1070,7 +1061,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection:clearing", "observation": { - "sender": ["c9e4131930e5", "aa1058fa6654", "afb61324f54a"], + "sender": ["47c387a75ffc", "aa1058fa6654", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -1084,7 +1075,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection:cleared", "observation": { - "sender": ["c9e4131930e5", "aa1058fa6654", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "aa1058fa6654", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -1098,7 +1089,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection-no-message:reported", "observation": { - "sender": ["c9e4131930e5", "60ae3b4c26a5"], + "sender": ["47c387a75ffc", "60ae3b4c26a5"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -1111,7 +1102,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection-no-message:clearing", "observation": { - "sender": ["c9e4131930e5", "60ae3b4c26a5", "afb61324f54a"], + "sender": ["47c387a75ffc", "60ae3b4c26a5", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -1125,7 +1116,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection-no-message:cleared", "observation": { - "sender": ["c9e4131930e5", "60ae3b4c26a5", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "60ae3b4c26a5", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", diff --git a/mobile/rpc-foundation/goldens/matrix-session.terminal-gesture-input-terminal.clearbuffer-1.json b/mobile/rpc-foundation/goldens/matrix-session.terminal-gesture-input-terminal.clearbuffer-1.json index b987894bdd0..14505cc14c0 100644 --- a/mobile/rpc-foundation/goldens/matrix-session.terminal-gesture-input-terminal.clearbuffer-1.json +++ b/mobile/rpc-foundation/goldens/matrix-session.terminal-gesture-input-terminal.clearbuffer-1.json @@ -170,6 +170,48 @@ "message": "Terminal cleared" } }, + "47c387a75ffc": { + "name": "terminal.send#1", + "ordinal": 1, + "args": [ + { + "name": "method", + "value": "terminal.send" + }, + { + "name": "params", + "value": { + "client": { + "id": "device-token-1", + "type": "mobile" + }, + "enter": false, + "terminal": "terminal-1", + "text": "\u001b[<64;10;5M" + } + }, + { + "name": "options", + "value": { + "failWhenDisconnected": true + } + } + ], + "settlement": { + "status": "fulfilled", + "startedAt": 0, + "settledAt": 16, + "value": { + "id": "frame-1", + "ok": true, + "result": { + "send": { + "accepted": true + } + } + } + } + }, "4dd92d5c81be": { "name": "terminal.clearBuffer#1", "ordinal": 5, @@ -352,15 +394,6 @@ "ordinal": 6, "json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"terminal.clearBuffer\",\"params\":{\"terminal\":\"terminal-1\"}}" }, - "93092a2f06c5": { - "bucketTokens": 63, - "crash": { - "$rpc": "null" - }, - "inFlight": false, - "queuedBytes": "\u001b[<64;10;5M", - "queuedSequences": 1 - }, "94ce15ec36dc": { "name": "orchestration.workerTerminalUserInput#1", "ordinal": 3, @@ -397,6 +430,38 @@ } } }, + "9fa6cd0b7fa0": { + "name": "terminal.send#1", + "ordinal": 1, + "args": [ + { + "name": "method", + "value": "terminal.send" + }, + { + "name": "params", + "value": { + "client": { + "id": "device-token-1", + "type": "mobile" + }, + "enter": false, + "terminal": "terminal-1", + "text": "\u001b[<64;10;5M" + } + }, + { + "name": "options", + "value": { + "failWhenDisconnected": true + } + } + ], + "settlement": { + "status": "pending", + "startedAt": 0 + } + }, "a2ee798dd5e4": { "name": "terminal.clearBuffer#1", "ordinal": 5, @@ -490,48 +555,6 @@ "startedAt": 16 } }, - "c9e4131930e5": { - "name": "terminal.send#1", - "ordinal": 1, - "args": [ - { - "name": "method", - "value": "terminal.send" - }, - { - "name": "params", - "value": { - "client": { - "id": "device-token-1", - "type": "mobile" - }, - "enter": false, - "terminal": "terminal-1", - "text": "\u001b[<64;10;5M" - } - }, - { - "name": "options", - "value": { - "failWhenDisconnected": true - } - } - ], - "settlement": { - "status": "fulfilled", - "startedAt": 16, - "settledAt": 16, - "value": { - "id": "frame-1", - "ok": true, - "result": { - "send": { - "accepted": true - } - } - } - } - }, "caa6ece1bdab": { "bucketTokens": 63, "crash": { @@ -629,38 +652,6 @@ "durationMs": 1500, "message": "Couldn't clear terminal" } - }, - "fd81ada317ab": { - "name": "terminal.send#1", - "ordinal": 1, - "args": [ - { - "name": "method", - "value": "terminal.send" - }, - { - "name": "params", - "value": { - "client": { - "id": "device-token-1", - "type": "mobile" - }, - "enter": false, - "terminal": "terminal-1", - "text": "\u001b[<64;10;5M" - } - }, - { - "name": "options", - "value": { - "failWhenDisconnected": true - } - } - ], - "settlement": { - "status": "pending", - "startedAt": 16 - } } }, "recording": { @@ -669,20 +660,20 @@ { "id": "terminal-gesture-flush-and-clear.prelude:queued", "observation": { - "sender": [], - "payloads": [], + "sender": ["9fa6cd0b7fa0"], + "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", "gesture": "eb79a9b3682a" }, - "state": "93092a2f06c5", + "state": "caa6ece1bdab", "effects": [] } }, { "id": "terminal-gesture-flush-and-clear.prelude:flushing", "observation": { - "sender": ["fd81ada317ab"], + "sender": ["9fa6cd0b7fa0"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -695,7 +686,7 @@ { "id": "terminal-gesture-flush-and-clear.prelude:sent", "observation": { - "sender": ["c9e4131930e5", "77d8a44e0dcc"], + "sender": ["47c387a75ffc", "77d8a44e0dcc"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -708,7 +699,7 @@ { "id": "terminal-gesture-flush-and-clear.prelude:reported", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc"], + "sender": ["47c387a75ffc", "94ce15ec36dc"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -721,7 +712,7 @@ { "id": "terminal-gesture-flush-and-clear.prelude:clearing", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "afb61324f54a"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -735,7 +726,7 @@ { "id": "terminal-gesture-flush-and-clear.prelude:cleanup", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "a2ee798dd5e4"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "a2ee798dd5e4"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -749,7 +740,7 @@ { "id": "terminal-gesture-flush-and-clear.normal:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -763,7 +754,7 @@ { "id": "terminal-gesture-flush-and-clear.result-absent:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "18f37862e26f"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "18f37862e26f"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -777,7 +768,7 @@ { "id": "terminal-gesture-flush-and-clear.result-null:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "4dd92d5c81be"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "4dd92d5c81be"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -791,7 +782,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-ok-missing:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "86e68519e4fc"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "86e68519e4fc"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -805,7 +796,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-string-error:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "13e21e9d5a19"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "13e21e9d5a19"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -819,7 +810,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-object-error:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "0db561233383"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "0db561233383"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -833,7 +824,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "af47e4950d3c"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "af47e4950d3c"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -847,7 +838,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused-no-message:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "52f4b33bfffe"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "52f4b33bfffe"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -861,7 +852,7 @@ { "id": "terminal-gesture-flush-and-clear.method-not-found:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "e9ab8b56056e"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "e9ab8b56056e"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -875,7 +866,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "85797d45b4ec"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "85797d45b4ec"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -889,7 +880,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection-no-message:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "14826318e3f0"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "14826318e3f0"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", diff --git a/mobile/rpc-foundation/goldens/matrix-session.terminal-gesture-input-terminal.send-1.json b/mobile/rpc-foundation/goldens/matrix-session.terminal-gesture-input-terminal.send-1.json index 6c22a77635d..a90bdebc532 100644 --- a/mobile/rpc-foundation/goldens/matrix-session.terminal-gesture-input-terminal.send-1.json +++ b/mobile/rpc-foundation/goldens/matrix-session.terminal-gesture-input-terminal.send-1.json @@ -4,7 +4,7 @@ "family": "session.terminal-gesture-input", "namedDeltas": [], "values": { - "070ef6f33862": { + "038694606b99": { "name": "terminal.send#1", "ordinal": 1, "args": [ @@ -33,15 +33,11 @@ ], "settlement": { "status": "fulfilled", - "startedAt": 16, + "startedAt": 0, "settledAt": 16, "value": { - "error": { - "code": "refused", - "message": "" - }, "id": "frame-1", - "ok": false + "ok": true } } }, @@ -92,103 +88,7 @@ } } }, - "1cb3848bdd54": { - "name": "terminal.send#1", - "ordinal": 1, - "args": [ - { - "name": "method", - "value": "terminal.send" - }, - { - "name": "params", - "value": { - "client": { - "id": "device-token-1", - "type": "mobile" - }, - "enter": false, - "terminal": "terminal-1", - "text": "\u001b[<64;10;5M" - } - }, - { - "name": "options", - "value": { - "failWhenDisconnected": true - } - } - ], - "settlement": { - "status": "fulfilled", - "startedAt": 16, - "settledAt": 16, - "value": { - "error": { - "code": "method_not_found", - "message": "Unknown method" - }, - "id": "frame-1", - "ok": false - } - } - }, - "204da356c8b7": { - "status": "fulfilled", - "startedAt": 16, - "settledAt": 16, - "value": { - "$rpc": "undefined" - } - }, - "38bc7ce28395": { - "name": "terminal.send#1", - "ordinal": 1, - "args": [ - { - "name": "method", - "value": "terminal.send" - }, - { - "name": "params", - "value": { - "client": { - "id": "device-token-1", - "type": "mobile" - }, - "enter": false, - "terminal": "terminal-1", - "text": "\u001b[<64;10;5M" - } - }, - { - "name": "options", - "value": { - "failWhenDisconnected": true - } - } - ], - "settlement": { - "status": "fulfilled", - "startedAt": 16, - "settledAt": 16, - "value": { - "id": "frame-1", - "ok": true - } - } - }, - "3dc7f55dee2a": { - "name": "toast", - "ordinal": 7, - "value": { - "durationMs": { - "$rpc": "null" - }, - "message": "Terminal cleared" - } - }, - "48418679db6b": { + "18ae72c963d5": { "name": "terminal.send#1", "ordinal": 1, "args": [ @@ -217,15 +117,199 @@ ], "settlement": { "status": "rejected", - "startedAt": 16, + "startedAt": 0, "settledAt": 16, "error": { "category": "Error", - "message": "", + "message": "transport failure", "isRpcDeliveryUnknown": true } } }, + "204da356c8b7": { + "status": "fulfilled", + "startedAt": 16, + "settledAt": 16, + "value": { + "$rpc": "undefined" + } + }, + "2198adee8c06": { + "name": "terminal.send#1", + "ordinal": 1, + "args": [ + { + "name": "method", + "value": "terminal.send" + }, + { + "name": "params", + "value": { + "client": { + "id": "device-token-1", + "type": "mobile" + }, + "enter": false, + "terminal": "terminal-1", + "text": "\u001b[<64;10;5M" + } + }, + { + "name": "options", + "value": { + "failWhenDisconnected": true + } + } + ], + "settlement": { + "status": "fulfilled", + "startedAt": 0, + "settledAt": 16, + "value": { + "id": "frame-1", + "ok": true, + "result": { + "error": { + "message": "inner refused" + }, + "ok": false + } + } + } + }, + "3a2f96d25da8": { + "name": "terminal.send#1", + "ordinal": 1, + "args": [ + { + "name": "method", + "value": "terminal.send" + }, + { + "name": "params", + "value": { + "client": { + "id": "device-token-1", + "type": "mobile" + }, + "enter": false, + "terminal": "terminal-1", + "text": "\u001b[<64;10;5M" + } + }, + { + "name": "options", + "value": { + "failWhenDisconnected": true + } + } + ], + "settlement": { + "status": "fulfilled", + "startedAt": 0, + "settledAt": 16, + "value": { + "id": "frame-1", + "ok": true, + "result": { + "$rpc": "null" + } + } + } + }, + "3ac9be406587": { + "name": "terminal.send#1", + "ordinal": 1, + "args": [ + { + "name": "method", + "value": "terminal.send" + }, + { + "name": "params", + "value": { + "client": { + "id": "device-token-1", + "type": "mobile" + }, + "enter": false, + "terminal": "terminal-1", + "text": "\u001b[<64;10;5M" + } + }, + { + "name": "options", + "value": { + "failWhenDisconnected": true + } + } + ], + "settlement": { + "status": "fulfilled", + "startedAt": 0, + "settledAt": 16, + "value": { + "id": "frame-1", + "ok": true, + "result": { + "error": "inner refused", + "ok": false + } + } + } + }, + "3dc7f55dee2a": { + "name": "toast", + "ordinal": 7, + "value": { + "durationMs": { + "$rpc": "null" + }, + "message": "Terminal cleared" + } + }, + "47c387a75ffc": { + "name": "terminal.send#1", + "ordinal": 1, + "args": [ + { + "name": "method", + "value": "terminal.send" + }, + { + "name": "params", + "value": { + "client": { + "id": "device-token-1", + "type": "mobile" + }, + "enter": false, + "terminal": "terminal-1", + "text": "\u001b[<64;10;5M" + } + }, + { + "name": "options", + "value": { + "failWhenDisconnected": true + } + } + ], + "settlement": { + "status": "fulfilled", + "startedAt": 0, + "settledAt": 16, + "value": { + "id": "frame-1", + "ok": true, + "result": { + "send": { + "accepted": true + } + } + } + } + }, "5ec72f058605": { "name": "terminal.clearBuffer#1", "ordinal": 3, @@ -252,128 +336,6 @@ "startedAt": 16 } }, - "656001024da8": { - "name": "terminal.send#1", - "ordinal": 1, - "args": [ - { - "name": "method", - "value": "terminal.send" - }, - { - "name": "params", - "value": { - "client": { - "id": "device-token-1", - "type": "mobile" - }, - "enter": false, - "terminal": "terminal-1", - "text": "\u001b[<64;10;5M" - } - }, - { - "name": "options", - "value": { - "failWhenDisconnected": true - } - } - ], - "settlement": { - "status": "fulfilled", - "startedAt": 16, - "settledAt": 16, - "value": { - "id": "frame-1", - "ok": true, - "result": { - "error": "inner refused", - "ok": false - } - } - } - }, - "72c5de3cd8b6": { - "name": "terminal.send#1", - "ordinal": 1, - "args": [ - { - "name": "method", - "value": "terminal.send" - }, - { - "name": "params", - "value": { - "client": { - "id": "device-token-1", - "type": "mobile" - }, - "enter": false, - "terminal": "terminal-1", - "text": "\u001b[<64;10;5M" - } - }, - { - "name": "options", - "value": { - "failWhenDisconnected": true - } - } - ], - "settlement": { - "status": "fulfilled", - "startedAt": 16, - "settledAt": 16, - "value": { - "id": "frame-1", - "ok": true, - "result": { - "error": "refused" - } - } - } - }, - "73ecd20f7d7d": { - "name": "terminal.send#1", - "ordinal": 1, - "args": [ - { - "name": "method", - "value": "terminal.send" - }, - { - "name": "params", - "value": { - "client": { - "id": "device-token-1", - "type": "mobile" - }, - "enter": false, - "terminal": "terminal-1", - "text": "\u001b[<64;10;5M" - } - }, - { - "name": "options", - "value": { - "failWhenDisconnected": true - } - } - ], - "settlement": { - "status": "fulfilled", - "startedAt": 16, - "settledAt": 16, - "value": { - "error": { - "code": "refused", - "message": "outer refused" - }, - "id": "frame-1", - "ok": false - } - } - }, "77d8a44e0dcc": { "name": "orchestration.workerTerminalUserInput#1", "ordinal": 3, @@ -402,7 +364,26 @@ "startedAt": 16 } }, - "7df6e5522a2f": { + "8224ccdb2cd8": { + "name": "terminal.send#1", + "ordinal": 2, + "json": "{\"id\":\"frame-1\",\"deviceToken\":\"recording-device\",\"method\":\"terminal.send\",\"params\":{\"terminal\":\"terminal-1\",\"text\":\"\\u001b[<64;10;5M\",\"enter\":false,\"client\":{\"id\":\"device-token-1\",\"type\":\"mobile\"}}}" + }, + "839dec95ae1c": { + "status": "pending", + "startedAt": 16 + }, + "85a38010bc83": { + "name": "orchestration.workerTerminalUserInput#1", + "ordinal": 4, + "json": "{\"id\":\"frame-2\",\"deviceToken\":\"recording-device\",\"method\":\"orchestration.workerTerminalUserInput\",\"params\":{\"terminal\":\"terminal-1\"}}" + }, + "8716af94ca80": { + "name": "terminal.clearBuffer#1", + "ordinal": 6, + "json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"terminal.clearBuffer\",\"params\":{\"terminal\":\"terminal-1\"}}" + }, + "8cc2f30cc0d2": { "name": "terminal.send#1", "ordinal": 1, "args": [ @@ -431,44 +412,57 @@ ], "settlement": { "status": "fulfilled", - "startedAt": 16, + "startedAt": 0, "settledAt": 16, "value": { "id": "frame-1", "ok": true, "result": { - "$rpc": "null" + "error": "refused" } } } }, - "8224ccdb2cd8": { + "8d84d72cf6d5": { "name": "terminal.send#1", - "ordinal": 2, - "json": "{\"id\":\"frame-1\",\"deviceToken\":\"recording-device\",\"method\":\"terminal.send\",\"params\":{\"terminal\":\"terminal-1\",\"text\":\"\\u001b[<64;10;5M\",\"enter\":false,\"client\":{\"id\":\"device-token-1\",\"type\":\"mobile\"}}}" - }, - "839dec95ae1c": { - "status": "pending", - "startedAt": 16 - }, - "85a38010bc83": { - "name": "orchestration.workerTerminalUserInput#1", - "ordinal": 4, - "json": "{\"id\":\"frame-2\",\"deviceToken\":\"recording-device\",\"method\":\"orchestration.workerTerminalUserInput\",\"params\":{\"terminal\":\"terminal-1\"}}" - }, - "8716af94ca80": { - "name": "terminal.clearBuffer#1", - "ordinal": 6, - "json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"terminal.clearBuffer\",\"params\":{\"terminal\":\"terminal-1\"}}" - }, - "93092a2f06c5": { - "bucketTokens": 63, - "crash": { - "$rpc": "null" - }, - "inFlight": false, - "queuedBytes": "\u001b[<64;10;5M", - "queuedSequences": 1 + "ordinal": 1, + "args": [ + { + "name": "method", + "value": "terminal.send" + }, + { + "name": "params", + "value": { + "client": { + "id": "device-token-1", + "type": "mobile" + }, + "enter": false, + "terminal": "terminal-1", + "text": "\u001b[<64;10;5M" + } + }, + { + "name": "options", + "value": { + "failWhenDisconnected": true + } + } + ], + "settlement": { + "status": "fulfilled", + "startedAt": 0, + "settledAt": 16, + "value": { + "error": { + "code": "refused", + "message": "outer refused" + }, + "id": "frame-1", + "ok": false + } + } }, "94ce15ec36dc": { "name": "orchestration.workerTerminalUserInput#1", @@ -506,6 +500,79 @@ } } }, + "94fa272beafb": { + "name": "terminal.send#1", + "ordinal": 1, + "args": [ + { + "name": "method", + "value": "terminal.send" + }, + { + "name": "params", + "value": { + "client": { + "id": "device-token-1", + "type": "mobile" + }, + "enter": false, + "terminal": "terminal-1", + "text": "\u001b[<64;10;5M" + } + }, + { + "name": "options", + "value": { + "failWhenDisconnected": true + } + } + ], + "settlement": { + "status": "fulfilled", + "startedAt": 0, + "settledAt": 16, + "value": { + "error": { + "code": "refused", + "message": "" + }, + "id": "frame-1", + "ok": false + } + } + }, + "9fa6cd0b7fa0": { + "name": "terminal.send#1", + "ordinal": 1, + "args": [ + { + "name": "method", + "value": "terminal.send" + }, + { + "name": "params", + "value": { + "client": { + "id": "device-token-1", + "type": "mobile" + }, + "enter": false, + "terminal": "terminal-1", + "text": "\u001b[<64;10;5M" + } + }, + { + "name": "options", + "value": { + "failWhenDisconnected": true + } + } + ], + "settlement": { + "status": "pending", + "startedAt": 0 + } + }, "a1ae5051ed70": { "name": "toast", "ordinal": 5, @@ -542,48 +609,6 @@ "startedAt": 16 } }, - "c9e4131930e5": { - "name": "terminal.send#1", - "ordinal": 1, - "args": [ - { - "name": "method", - "value": "terminal.send" - }, - { - "name": "params", - "value": { - "client": { - "id": "device-token-1", - "type": "mobile" - }, - "enter": false, - "terminal": "terminal-1", - "text": "\u001b[<64;10;5M" - } - }, - { - "name": "options", - "value": { - "failWhenDisconnected": true - } - } - ], - "settlement": { - "status": "fulfilled", - "startedAt": 16, - "settledAt": 16, - "value": { - "id": "frame-1", - "ok": true, - "result": { - "send": { - "accepted": true - } - } - } - } - }, "caa6ece1bdab": { "bucketTokens": 63, "crash": { @@ -597,50 +622,12 @@ "$rpc": "null" } }, - "cdd4542679ff": { - "name": "terminal.send#1", - "ordinal": 1, - "args": [ - { - "name": "method", - "value": "terminal.send" - }, - { - "name": "params", - "value": { - "client": { - "id": "device-token-1", - "type": "mobile" - }, - "enter": false, - "terminal": "terminal-1", - "text": "\u001b[<64;10;5M" - } - }, - { - "name": "options", - "value": { - "failWhenDisconnected": true - } - } - ], - "settlement": { - "status": "rejected", - "startedAt": 16, - "settledAt": 16, - "error": { - "category": "Error", - "message": "transport failure", - "isRpcDeliveryUnknown": true - } - } - }, "d9c52be2f839": { "name": "terminal.clearBuffer#1", "ordinal": 4, "json": "{\"id\":\"frame-2\",\"deviceToken\":\"recording-device\",\"method\":\"terminal.clearBuffer\",\"params\":{\"terminal\":\"terminal-1\"}}" }, - "de2d526b46eb": { + "e1076775e5c2": { "name": "terminal.send#1", "ordinal": 1, "args": [ @@ -669,17 +656,15 @@ ], "settlement": { "status": "fulfilled", - "startedAt": 16, + "startedAt": 0, "settledAt": 16, "value": { + "error": { + "code": "method_not_found", + "message": "Unknown method" + }, "id": "frame-1", - "ok": true, - "result": { - "error": { - "message": "inner refused" - }, - "ok": false - } + "ok": false } } }, @@ -725,7 +710,7 @@ } } }, - "fd81ada317ab": { + "eecb4c1a0308": { "name": "terminal.send#1", "ordinal": 1, "args": [ @@ -753,8 +738,14 @@ } ], "settlement": { - "status": "pending", - "startedAt": 16 + "status": "rejected", + "startedAt": 0, + "settledAt": 16, + "error": { + "category": "Error", + "message": "", + "isRpcDeliveryUnknown": true + } } } }, @@ -764,20 +755,20 @@ { "id": "terminal-gesture-flush-and-clear.prelude:queued", "observation": { - "sender": [], - "payloads": [], + "sender": ["9fa6cd0b7fa0"], + "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", "gesture": "eb79a9b3682a" }, - "state": "93092a2f06c5", + "state": "caa6ece1bdab", "effects": [] } }, { "id": "terminal-gesture-flush-and-clear.prelude:flushing", "observation": { - "sender": ["fd81ada317ab"], + "sender": ["9fa6cd0b7fa0"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -790,7 +781,7 @@ { "id": "terminal-gesture-flush-and-clear.normal:sent", "observation": { - "sender": ["c9e4131930e5", "77d8a44e0dcc"], + "sender": ["47c387a75ffc", "77d8a44e0dcc"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -803,7 +794,7 @@ { "id": "terminal-gesture-flush-and-clear.normal:reported", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc"], + "sender": ["47c387a75ffc", "94ce15ec36dc"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -816,7 +807,7 @@ { "id": "terminal-gesture-flush-and-clear.normal:clearing", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "afb61324f54a"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -830,7 +821,7 @@ { "id": "terminal-gesture-flush-and-clear.normal:cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -844,7 +835,7 @@ { "id": "terminal-gesture-flush-and-clear.result-absent:sent", "observation": { - "sender": ["38bc7ce28395"], + "sender": ["038694606b99"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -857,7 +848,7 @@ { "id": "terminal-gesture-flush-and-clear.result-absent:reported", "observation": { - "sender": ["38bc7ce28395"], + "sender": ["038694606b99"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -870,7 +861,7 @@ { "id": "terminal-gesture-flush-and-clear.result-absent:clearing", "observation": { - "sender": ["38bc7ce28395", "5ec72f058605"], + "sender": ["038694606b99", "5ec72f058605"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -884,7 +875,7 @@ { "id": "terminal-gesture-flush-and-clear.result-absent:cleared", "observation": { - "sender": ["38bc7ce28395", "165d659fda65"], + "sender": ["038694606b99", "165d659fda65"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -898,7 +889,7 @@ { "id": "terminal-gesture-flush-and-clear.result-null:sent", "observation": { - "sender": ["7df6e5522a2f"], + "sender": ["3a2f96d25da8"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -911,7 +902,7 @@ { "id": "terminal-gesture-flush-and-clear.result-null:reported", "observation": { - "sender": ["7df6e5522a2f"], + "sender": ["3a2f96d25da8"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -924,7 +915,7 @@ { "id": "terminal-gesture-flush-and-clear.result-null:clearing", "observation": { - "sender": ["7df6e5522a2f", "5ec72f058605"], + "sender": ["3a2f96d25da8", "5ec72f058605"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -938,7 +929,7 @@ { "id": "terminal-gesture-flush-and-clear.result-null:cleared", "observation": { - "sender": ["7df6e5522a2f", "165d659fda65"], + "sender": ["3a2f96d25da8", "165d659fda65"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -952,7 +943,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-ok-missing:sent", "observation": { - "sender": ["72c5de3cd8b6"], + "sender": ["8cc2f30cc0d2"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -965,7 +956,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-ok-missing:reported", "observation": { - "sender": ["72c5de3cd8b6"], + "sender": ["8cc2f30cc0d2"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -978,7 +969,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-ok-missing:clearing", "observation": { - "sender": ["72c5de3cd8b6", "5ec72f058605"], + "sender": ["8cc2f30cc0d2", "5ec72f058605"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -992,7 +983,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-ok-missing:cleared", "observation": { - "sender": ["72c5de3cd8b6", "165d659fda65"], + "sender": ["8cc2f30cc0d2", "165d659fda65"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1006,7 +997,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-string-error:sent", "observation": { - "sender": ["656001024da8"], + "sender": ["3ac9be406587"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1019,7 +1010,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-string-error:reported", "observation": { - "sender": ["656001024da8"], + "sender": ["3ac9be406587"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1032,7 +1023,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-string-error:clearing", "observation": { - "sender": ["656001024da8", "5ec72f058605"], + "sender": ["3ac9be406587", "5ec72f058605"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1046,7 +1037,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-string-error:cleared", "observation": { - "sender": ["656001024da8", "165d659fda65"], + "sender": ["3ac9be406587", "165d659fda65"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1060,7 +1051,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-object-error:sent", "observation": { - "sender": ["de2d526b46eb"], + "sender": ["2198adee8c06"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1073,7 +1064,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-object-error:reported", "observation": { - "sender": ["de2d526b46eb"], + "sender": ["2198adee8c06"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1086,7 +1077,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-object-error:clearing", "observation": { - "sender": ["de2d526b46eb", "5ec72f058605"], + "sender": ["2198adee8c06", "5ec72f058605"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1100,7 +1091,7 @@ { "id": "terminal-gesture-flush-and-clear.inner-false-object-error:cleared", "observation": { - "sender": ["de2d526b46eb", "165d659fda65"], + "sender": ["2198adee8c06", "165d659fda65"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1114,7 +1105,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused:sent", "observation": { - "sender": ["73ecd20f7d7d"], + "sender": ["8d84d72cf6d5"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1127,7 +1118,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused:reported", "observation": { - "sender": ["73ecd20f7d7d"], + "sender": ["8d84d72cf6d5"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1140,7 +1131,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused:clearing", "observation": { - "sender": ["73ecd20f7d7d", "5ec72f058605"], + "sender": ["8d84d72cf6d5", "5ec72f058605"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1154,7 +1145,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused:cleared", "observation": { - "sender": ["73ecd20f7d7d", "165d659fda65"], + "sender": ["8d84d72cf6d5", "165d659fda65"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1168,7 +1159,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused-no-message:sent", "observation": { - "sender": ["070ef6f33862"], + "sender": ["94fa272beafb"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1181,7 +1172,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused-no-message:reported", "observation": { - "sender": ["070ef6f33862"], + "sender": ["94fa272beafb"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1194,7 +1185,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused-no-message:clearing", "observation": { - "sender": ["070ef6f33862", "5ec72f058605"], + "sender": ["94fa272beafb", "5ec72f058605"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1208,7 +1199,7 @@ { "id": "terminal-gesture-flush-and-clear.outer-refused-no-message:cleared", "observation": { - "sender": ["070ef6f33862", "165d659fda65"], + "sender": ["94fa272beafb", "165d659fda65"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1222,7 +1213,7 @@ { "id": "terminal-gesture-flush-and-clear.method-not-found:sent", "observation": { - "sender": ["1cb3848bdd54"], + "sender": ["e1076775e5c2"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1235,7 +1226,7 @@ { "id": "terminal-gesture-flush-and-clear.method-not-found:reported", "observation": { - "sender": ["1cb3848bdd54"], + "sender": ["e1076775e5c2"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1248,7 +1239,7 @@ { "id": "terminal-gesture-flush-and-clear.method-not-found:clearing", "observation": { - "sender": ["1cb3848bdd54", "5ec72f058605"], + "sender": ["e1076775e5c2", "5ec72f058605"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1262,7 +1253,7 @@ { "id": "terminal-gesture-flush-and-clear.method-not-found:cleared", "observation": { - "sender": ["1cb3848bdd54", "165d659fda65"], + "sender": ["e1076775e5c2", "165d659fda65"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1276,7 +1267,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection:sent", "observation": { - "sender": ["cdd4542679ff"], + "sender": ["18ae72c963d5"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1289,7 +1280,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection:reported", "observation": { - "sender": ["cdd4542679ff"], + "sender": ["18ae72c963d5"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1302,7 +1293,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection:clearing", "observation": { - "sender": ["cdd4542679ff", "5ec72f058605"], + "sender": ["18ae72c963d5", "5ec72f058605"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1316,7 +1307,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection:cleared", "observation": { - "sender": ["cdd4542679ff", "165d659fda65"], + "sender": ["18ae72c963d5", "165d659fda65"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1330,7 +1321,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection-no-message:sent", "observation": { - "sender": ["48418679db6b"], + "sender": ["eecb4c1a0308"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1343,7 +1334,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection-no-message:reported", "observation": { - "sender": ["48418679db6b"], + "sender": ["eecb4c1a0308"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -1356,7 +1347,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection-no-message:clearing", "observation": { - "sender": ["48418679db6b", "5ec72f058605"], + "sender": ["eecb4c1a0308", "5ec72f058605"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", @@ -1370,7 +1361,7 @@ { "id": "terminal-gesture-flush-and-clear.transport-rejection-no-message:cleared", "observation": { - "sender": ["48418679db6b", "165d659fda65"], + "sender": ["eecb4c1a0308", "165d659fda65"], "payloads": ["8224ccdb2cd8", "d9c52be2f839"], "settlements": { "mount": "eb79a9b3682a", diff --git a/mobile/rpc-foundation/goldens/terminal-gesture-flush-and-clear.json b/mobile/rpc-foundation/goldens/terminal-gesture-flush-and-clear.json index 152ff6c6ccc..1692ab6a12b 100644 --- a/mobile/rpc-foundation/goldens/terminal-gesture-flush-and-clear.json +++ b/mobile/rpc-foundation/goldens/terminal-gesture-flush-and-clear.json @@ -35,6 +35,48 @@ "message": "Terminal cleared" } }, + "47c387a75ffc": { + "name": "terminal.send#1", + "ordinal": 1, + "args": [ + { + "name": "method", + "value": "terminal.send" + }, + { + "name": "params", + "value": { + "client": { + "id": "device-token-1", + "type": "mobile" + }, + "enter": false, + "terminal": "terminal-1", + "text": "\u001b[<64;10;5M" + } + }, + { + "name": "options", + "value": { + "failWhenDisconnected": true + } + } + ], + "settlement": { + "status": "fulfilled", + "startedAt": 0, + "settledAt": 16, + "value": { + "id": "frame-1", + "ok": true, + "result": { + "send": { + "accepted": true + } + } + } + } + }, "77d8a44e0dcc": { "name": "orchestration.workerTerminalUserInput#1", "ordinal": 3, @@ -82,15 +124,6 @@ "ordinal": 6, "json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"terminal.clearBuffer\",\"params\":{\"terminal\":\"terminal-1\"}}" }, - "93092a2f06c5": { - "bucketTokens": 63, - "crash": { - "$rpc": "null" - }, - "inFlight": false, - "queuedBytes": "\u001b[<64;10;5M", - "queuedSequences": 1 - }, "94ce15ec36dc": { "name": "orchestration.workerTerminalUserInput#1", "ordinal": 3, @@ -127,33 +160,7 @@ } } }, - "afb61324f54a": { - "name": "terminal.clearBuffer#1", - "ordinal": 5, - "args": [ - { - "name": "method", - "value": "terminal.clearBuffer" - }, - { - "name": "params", - "value": { - "terminal": "terminal-1" - } - }, - { - "name": "options", - "value": { - "$rpc": "absent" - } - } - ], - "settlement": { - "status": "pending", - "startedAt": 16 - } - }, - "c9e4131930e5": { + "9fa6cd0b7fa0": { "name": "terminal.send#1", "ordinal": 1, "args": [ @@ -181,18 +188,34 @@ } ], "settlement": { - "status": "fulfilled", - "startedAt": 16, - "settledAt": 16, - "value": { - "id": "frame-1", - "ok": true, - "result": { - "send": { - "accepted": true - } + "status": "pending", + "startedAt": 0 + } + }, + "afb61324f54a": { + "name": "terminal.clearBuffer#1", + "ordinal": 5, + "args": [ + { + "name": "method", + "value": "terminal.clearBuffer" + }, + { + "name": "params", + "value": { + "terminal": "terminal-1" + } + }, + { + "name": "options", + "value": { + "$rpc": "absent" } } + ], + "settlement": { + "status": "pending", + "startedAt": 16 } }, "caa6ece1bdab": { @@ -249,38 +272,6 @@ } } } - }, - "fd81ada317ab": { - "name": "terminal.send#1", - "ordinal": 1, - "args": [ - { - "name": "method", - "value": "terminal.send" - }, - { - "name": "params", - "value": { - "client": { - "id": "device-token-1", - "type": "mobile" - }, - "enter": false, - "terminal": "terminal-1", - "text": "\u001b[<64;10;5M" - } - }, - { - "name": "options", - "value": { - "failWhenDisconnected": true - } - } - ], - "settlement": { - "status": "pending", - "startedAt": 16 - } } }, "recording": { @@ -289,20 +280,20 @@ { "id": "queued", "observation": { - "sender": [], - "payloads": [], + "sender": ["9fa6cd0b7fa0"], + "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", "gesture": "eb79a9b3682a" }, - "state": "93092a2f06c5", + "state": "caa6ece1bdab", "effects": [] } }, { "id": "flushing", "observation": { - "sender": ["fd81ada317ab"], + "sender": ["9fa6cd0b7fa0"], "payloads": ["8224ccdb2cd8"], "settlements": { "mount": "eb79a9b3682a", @@ -315,7 +306,7 @@ { "id": "sent", "observation": { - "sender": ["c9e4131930e5", "77d8a44e0dcc"], + "sender": ["47c387a75ffc", "77d8a44e0dcc"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -328,7 +319,7 @@ { "id": "reported", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc"], + "sender": ["47c387a75ffc", "94ce15ec36dc"], "payloads": ["8224ccdb2cd8", "85a38010bc83"], "settlements": { "mount": "eb79a9b3682a", @@ -341,7 +332,7 @@ { "id": "clearing", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "afb61324f54a"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "afb61324f54a"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", @@ -355,7 +346,7 @@ { "id": "cleared", "observation": { - "sender": ["c9e4131930e5", "94ce15ec36dc", "ebaa6b64425b"], + "sender": ["47c387a75ffc", "94ce15ec36dc", "ebaa6b64425b"], "payloads": ["8224ccdb2cd8", "85a38010bc83", "8716af94ca80"], "settlements": { "mount": "eb79a9b3682a", diff --git a/mobile/src/session/mobile-session-route-helpers.ts b/mobile/src/session/mobile-session-route-helpers.ts index 413e1316beb..e42d3367394 100644 --- a/mobile/src/session/mobile-session-route-helpers.ts +++ b/mobile/src/session/mobile-session-route-helpers.ts @@ -12,7 +12,6 @@ export const MOBILE_SESSION_STATUS_LABELS: Record = { export const TERMINAL_GESTURE_INPUT_BUCKET_CAPACITY = 64 export const TERMINAL_GESTURE_INPUT_REFILL_PER_SECOND = 120 -export const TERMINAL_GESTURE_INPUT_FLUSH_DELAY_MS = 16 export const TERMINAL_GESTURE_INPUT_MAX_PENDING_SEQUENCES = 32 export const TERMINAL_GESTURE_INPUT_MAX_QUEUE_AGE_MS = 250 diff --git a/mobile/src/session/terminal-gesture-input-delivery.test.ts b/mobile/src/session/terminal-gesture-input-delivery.test.ts new file mode 100644 index 00000000000..eba2efe9a1d --- /dev/null +++ b/mobile/src/session/terminal-gesture-input-delivery.test.ts @@ -0,0 +1,152 @@ +import { afterEach, beforeEach, expect, it, vi } from 'vitest' +import { createElement } from 'react' +import { act, create, type ReactTestRenderer } from 'react-test-renderer' +import { useMobileSessionTerminalInput } from './use-mobile-session-terminal-input' +import { terminalInputSend } from '../terminal/mobile-terminal-operations' +import type { ConnectionState } from '../transport/types' + +vi.mock('../terminal/mobile-terminal-operations', () => ({ + terminalInputSend: { + request: vi.fn(), + interpret: (response: { result: { send: { accepted: boolean } } }) => + response.result.send.accepted + }, + terminalBufferClear: {} +})) +vi.mock('../terminal/worker-terminal-takeover-report', () => ({ + reportWorkerTerminalUserInput: vi.fn() +})) + +const handle = 'term-gesture' +const up = '\x1b[A' +const down = '\x1b[B' +const ref = (current: T) => ({ current }) +const request = vi.mocked(terminalInputSend.request) +const renderers: ReactTestRenderer[] = [] +const accepted: Awaited> = { + id: 'synthetic-rpc', + ok: true, + result: { send: { accepted: true } } +} + +function fixture() { + const client = {} + const scope = { + client, + clientRef: ref(client), + connState: 'connected', + connStateRef: ref('connected'), + activeHandle: handle, + activeHandleRef: ref(handle), + activeSessionTabTypeRef: ref('terminal'), + ptyModesRef: ref(new Map([[handle, { altScreen: true }]])), + terminalGestureInputBucketsRef: ref(new Map()), + terminalGestureInputQueuesRef: ref(new Map()), + terminalGestureInputInFlightRef: ref(new Set()), + deviceTokenRef: ref('synthetic-device') + } + let actions!: ReturnType + function Harness() { + actions = useMobileSessionTerminalInput( + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: this fixture supplies every field reached by the gesture path; unrelated controller capabilities are not invoked. + scope as unknown as Parameters[0] + ) + return null + } + act(() => { + renderers.push(create(createElement(Harness))) + }) + return { actions, scope } +} + +function holdFirstRequest() { + let release!: () => void + const pending = new Promise((resolve) => { + release = () => resolve(accepted) + }) + request.mockReturnValueOnce(pending) + return release +} + +async function settle() { + await vi.advanceTimersByTimeAsync(0) +} + +beforeEach(() => { + vi.useFakeTimers() + request.mockReset() + request.mockResolvedValue(accepted) +}) +afterEach(() => { + act(() => renderers.splice(0).forEach((renderer) => renderer.unmount())) + vi.clearAllTimers() + vi.useRealTimers() +}) + +it('sends the first scroll input without waiting for a timer', async () => { + const { actions } = fixture() + await actions.handleTerminalInput(handle, up) + expect(request).toHaveBeenCalledTimes(1) + expect(request).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ terminal: handle, text: up, enter: false }), + expect.anything() + ) +}) + +it('keeps one request in flight and drains later movement in order after its acknowledgement', async () => { + const release = holdFirstRequest() + const { actions } = fixture() + await actions.handleTerminalInput(handle, up) + await actions.handleTerminalInput(handle, down) + await actions.handleTerminalInput(handle, up) + expect(request).toHaveBeenCalledTimes(1) + await vi.advanceTimersByTimeAsync(16) + expect(request).toHaveBeenCalledTimes(1) + release() + await settle() + expect(request).toHaveBeenCalledTimes(2) + expect(request.mock.calls.map((call) => call[1])).toEqual([ + expect.objectContaining({ text: up }), + expect.objectContaining({ text: down + up }) + ]) +}) + +it.each(['disconnected', 'inactive', 'expired'] as const)( + 'drops queued movement that becomes %s before the preceding request settles', + async (reason) => { + const release = holdFirstRequest() + const { actions, scope } = fixture() + await actions.handleTerminalInput(handle, up) + await actions.handleTerminalInput(handle, down) + if (reason === 'disconnected') { + scope.connStateRef.current = 'reconnecting' + } + if (reason === 'inactive') { + scope.activeHandleRef.current = 'another-terminal' + } + if (reason === 'expired') { + await vi.advanceTimersByTimeAsync(251) + } + release() + await settle() + expect(request).toHaveBeenCalledTimes(1) + expect(scope.terminalGestureInputQueuesRef.current.size).toBe(0) + } +) + +it('retains gesture validation and the per-sequence rate limit', async () => { + const release = holdFirstRequest() + const { actions } = fixture() + await actions.handleTerminalInput(handle, 'plain text') + await actions.handleTerminalInput('another-terminal', up) + expect(request).not.toHaveBeenCalled() + await actions.handleTerminalInput(handle, up.repeat(32)) + await actions.handleTerminalInput(handle, down.repeat(32)) + await actions.handleTerminalInput(handle, up) + expect(request).toHaveBeenCalledTimes(1) + release() + await settle() + expect(request).toHaveBeenCalledTimes(2) + expect(request.mock.calls[1]?.[1]).toEqual(expect.objectContaining({ text: down.repeat(32) })) +}) diff --git a/mobile/src/session/use-mobile-session-terminal-input.ts b/mobile/src/session/use-mobile-session-terminal-input.ts index f90563e443d..dd186a657ef 100644 --- a/mobile/src/session/use-mobile-session-terminal-input.ts +++ b/mobile/src/session/use-mobile-session-terminal-input.ts @@ -14,7 +14,6 @@ import { countTerminalGestureInputSequences } from '../terminal/terminal-gesture import { isGestureMouseTrackingMode, TERMINAL_GESTURE_INPUT_BUCKET_CAPACITY, - TERMINAL_GESTURE_INPUT_FLUSH_DELAY_MS, TERMINAL_GESTURE_INPUT_MAX_PENDING_SEQUENCES, TERMINAL_GESTURE_INPUT_MAX_QUEUE_AGE_MS, TERMINAL_GESTURE_INPUT_REFILL_PER_SECOND @@ -154,6 +153,9 @@ export function useMobileSessionTerminalInput(scope: MobileSessionFileActionsMod current.bytes += bytes current.sequenceCount += sequenceCount current.lastUpdatedMs = now + if (!terminalGestureInputInFlightRef.current.has(handle)) { + void flushTerminalGestureInput(handle) + } return } @@ -168,10 +170,6 @@ export function useMobileSessionTerminalInput(scope: MobileSessionFileActionsMod current.bytes += bytes current.sequenceCount += sequenceCount current.lastUpdatedMs = now - current.timer = setTimeout(() => { - current.timer = null - void flushTerminalGestureInput(handle) - }, TERMINAL_GESTURE_INPUT_FLUSH_DELAY_MS) return } } @@ -182,11 +180,11 @@ export function useMobileSessionTerminalInput(scope: MobileSessionFileActionsMod timer: null, lastUpdatedMs: now } - queued.timer = setTimeout(() => { - queued.timer = null - void flushTerminalGestureInput(handle) - }, TERMINAL_GESTURE_INPUT_FLUSH_DELAY_MS) terminalGestureInputQueuesRef.current.set(handle, queued) + // Send the leading edge now; an in-flight request's acknowledgement drains later movement. + if (!terminalGestureInputInFlightRef.current.has(handle)) { + void flushTerminalGestureInput(handle) + } }, [flushTerminalGestureInput] )