oficina / meet Public

native-browser: retry the chat probes across stream renewals

Chat is not replayed to a recipient whose stream is renewing, and the
gate renews every ten seconds; since the camera steps went in, the chat
exchange runs after the first renewal and under load loses a line to the
gap. Three tries each way; a chat path that is really broken still fails.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 06dbbba44ce87c3b4087f06b43431d60822a5465 parent 03dd077
1 file changed, +30 −6
  • test/browser/native.mjs +30 −6
diff --git a/test/browser/native.mjs b/test/browser/native.mjs
index e7a19b5..e64991e 100644
--- a/test/browser/native.mjs
+++ b/test/browser/native.mjs
@@ -171,12 +171,36 @@ try {
assert.equal(sample.stats.peerConnections, 1, 'recovering the camera keeps the same peer connection');
console.log('PASS a stalled camera was restarted and the far side kept its picture');
}
- await page.locator('[data-chat-text]').fill('browser chat probe');
- await page.locator('[data-chat-send]').click();
- await wait(() => sample?.receivedChatProbe === true, 'native displays browser chat');
- native.stdin.write('chat\n');
- await wait(() => chatCommandHandled, 'native handles send-chat command');
- await page.locator('[data-chat-log]').getByText('native chat probe', { exact: true }).waitFor();
+ // Chat is not replayed to a recipient whose stream is renewing (§6), and
+ // in this mode the stream renews every ten seconds, so a line that lands
+ // in a renewal's gap is lost by design. Since the camera steps above went
+ // in, chat runs well after the first renewal, and under load the gap is
+ // wide enough to catch it (2026-09-25: both subtests failed here on an
+ // unchanged tree, then passed alone and in a full run). Each direction
+ // gets three tries; a line that never arrives still fails.
+ for (let attempt = 1; ; attempt++) {
+ await page.locator('[data-chat-text]').fill('browser chat probe');
+ await page.locator('[data-chat-send]').click();
+ try {
+ await wait(() => sample?.receivedChatProbe === true, 'native displays browser chat', 8);
+ break;
+ } catch (err) {
+ if (attempt === 3) throw err;
+ console.log('RETRY browser chat probe, attempt', attempt + 1);
+ }
+ }
+ for (let attempt = 1; ; attempt++) {
+ native.stdin.write('chat\n');
+ await wait(() => chatCommandHandled, 'native handles send-chat command');
+ try {
+ await page.locator('[data-chat-log]').getByText('native chat probe', { exact: true }).first()
+ .waitFor({ timeout: 8000 });
+ break;
+ } catch (err) {
+ if (attempt === 3) throw err;
+ console.log('RETRY native chat probe, attempt', attempt + 1);
+ }
+ }
await wait(() => sample?.sentChatProbe === true, 'native displays accepted outgoing chat');
console.log('PASS chat delivered from browser to native and native to browser');
// Spec §15.19 across the two clients: the app's mute reaches the