@rubytech/create-realagent-code 0.1.614 → 0.1.615

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-realagent-code",
3
- "version": "0.1.614",
3
+ "version": "0.1.615",
4
4
  "description": "Install Real Agent — Built for agents. By agents.",
5
5
  "bin": {
6
6
  "create-realagent-code": "./dist/index.js"
@@ -9,6 +9,11 @@ Invoked by the admin agent directly.
9
9
 
10
10
  This is the platform's release timeline, newest first. Each entry shows the date it shipped and the version it shipped in, so you can tell the operator how current their install is. To compare, read the installed version from `capabilities-here` and match it against the versions below. Keep answers high level and in plain English; this is a summary, not a full commit log.
11
11
 
12
+ ## 2026-08-17 (0.1.615)
13
+
14
+ - An install that shows the browser on a connected screen now runs the right browser, and brings it back when it stops. One setting is the authority for which mode is in use, and both modes are supervised.
15
+ - Headless browsers left behind by other tools are now counted every hour, with the profile that launched each one named. They accumulated on a machine with nothing identifying where they came from; a browser this platform supervises is excluded.
16
+
12
17
  ## 2026-08-16 (0.1.614)
13
18
 
14
19
  - A routine that woke the assistant is no longer counted as having reached you. A wake is now recorded as a wake, and a run records the message that actually arrived in the chat, checked against what was really sent.
@@ -129,4 +129,4 @@ All tools are admin-allowlisted; none are exposed to public chat.
129
129
 
130
130
  ## Observability
131
131
 
132
- A successful render emits `[browser-render] url=… rendered=true domBytes=…` on the server's stderr (captured by the mcp-spawn-tee log). Every other tool returns a structured outcome: `ok`, or one of `cdp-unreachable`, `session-lost`, `selector-not-found`, `option-not-found`, `wait-timeout`, `navigate-failed`, `load-timeout`, `evaluate-failed`, `command-timeout`, `pdf-failed`, `screenshot-failed`, `unsupported-key`. On a device with no running Chromium (e.g. a laptop native-display install with no VNC browser) the tools return `cdp-unreachable` rather than hanging. In virtual-display mode a Chromium that dies while the VNC display stays up is self-healing: the brand's standing CDP-liveness check (run each `rss-sampler` cycle via `vnc.sh cdp-liveness`) relaunches it and logs `[vnc] op=cdp-liveness … reachable=<bool>` plus `[vnc] op=chromium-respawn … outcome=<ready|failed>` to the service journal, so `cdp-unreachable` is transient (recovered within the check interval, bounded against hot-looping an unlaunchable browser) rather than dead-until-restart. Native-display installs launch Chromium on-demand, so a `cdp-unreachable` there clears on the next browser call.
132
+ A successful render emits `[browser-render] url=… rendered=true domBytes=…` on the server's stderr (captured by the mcp-spawn-tee log). Every other tool returns a structured outcome: `ok`, or one of `cdp-unreachable`, `session-lost`, `selector-not-found`, `option-not-found`, `wait-timeout`, `navigate-failed`, `load-timeout`, `evaluate-failed`, `command-timeout`, `pdf-failed`, `screenshot-failed`, `unsupported-key`. On a device with no running Chromium the tools return `cdp-unreachable` rather than hanging. In **both** display modes a Chromium that dies is self-healing: the brand's standing CDP-liveness check (run each `rss-sampler` cycle via `vnc.sh cdp-liveness`) relaunches it and logs `[vnc] op=cdp-liveness display-mode=<virtual|native> … reachable=<bool>` plus `[vnc] op=chromium-respawn display-mode=<mode> … outcome=<ready|failed>` to the service journal, so `cdp-unreachable` is transient (recovered within the check interval, bounded against hot-looping an unlaunchable browser) rather than dead-until-restart. The launch precondition differs: virtual needs the brand's Xtigervnc display up, native needs an active local graphical session, and a native install with no such session emits `outcome=declined reason=no-graphical-session` each cycle instead of launching. The check was previously a silent no-op on native installs, and this file claimed a `cdp-unreachable` there cleared on the next browser call; it did not — the on-demand launcher is reachable only from the admin browser-pane route and onboarding, both of which need an operator, so an agent's browser call found no browser and nothing started one.
@@ -1,20 +1,25 @@
1
1
  #!/usr/bin/env bash
2
2
  # Bash harness for vnc.sh `cdp-liveness` — the standing Chromium respawn
3
- # supervisor (Task 1191).
3
+ # supervisor (Task 1191), extended to both display modes by Task 2780.
4
4
  #
5
- # The supervisor reconciles expected-vs-actual: when the VNC display is up but
6
- # the automation Chromium's CDP port is unreachable, it re-runs the brand's
7
- # start_chrome path so a Chromium that died is restored WITHOUT a brand-service
8
- # restart, bounded so an unlaunchable Chromium never hot-loops.
5
+ # The supervisor reconciles expected-vs-actual: when the automation Chromium's
6
+ # CDP port is unreachable but the mode's launch precondition holds, it re-runs
7
+ # that mode's start path so a Chromium that died is restored WITHOUT a
8
+ # brand-service restart, bounded so an unlaunchable Chromium never hot-loops.
9
9
  #
10
- # Determinism without a real browser or real ports: the test injects three
11
- # fakes onto the PATH used FOR THE vnc.sh SUBPROCESS ONLY (never the harness's
12
- # own PATH):
10
+ # Determinism without a real browser, real ports or a real login session: the
11
+ # test injects fakes onto the PATH used FOR THE vnc.sh SUBPROCESS ONLY (never
12
+ # the harness's own PATH):
13
13
  # ss — reports a port as LISTEN iff it appears in $STATE_DIR/ports.
14
14
  # sleep — collapses vnc.sh's port-wait loop to ~0.02s/iteration.
15
15
  # chromium-stub — records each launch in $STATE_DIR/chromium-calls and, in
16
16
  # "ready" mode, writes the CDP port into $STATE_DIR/ports so
17
17
  # the next ss probe sees it. "fail" mode never opens the port.
18
+ # loginctl — answers list-sessions / show-session from $STATE_DIR/sessions,
19
+ # one `id|active|remote|type|display` row per line, so session
20
+ # selection is exercised without a real seat (Task 2780).
21
+ # Xtigervnc — opens the rfb port so the `start` path can be driven.
22
+ # websockify — opens the websockify port for the same reason.
18
23
  # RESPAWN_MAX_FAILS / RESPAWN_COOLDOWN_SECS are passed to vnc.sh so the backoff
19
24
  # state machine is exercised without waiting real minutes.
20
25
  #
@@ -24,7 +29,15 @@
24
29
  # 3. repeated unreachable cycles → respawn capped at MAX, then cooldown
25
30
  # (no hot-loop on an unlaunchable browser).
26
31
  # 4. cooldown elapses → one further respawn attempt (not stuck).
27
- # 5. native DISPLAY_MODE → no line emitted, zero respawns.
32
+ # 6. virtual respawn is headed on the brand display.
33
+ # …and the Task 2780 surface:
34
+ # 5. native + CDP up → a line carrying display-mode=native.
35
+ # 7. native + CDP down + a session → one native respawn, on the session's own
36
+ # display.
37
+ # 8. native + no local graphical session → declines, launches nothing, and
38
+ # says so.
39
+ # 9. session selection is by evidence, not by row order.
40
+ # 10. `vnc.sh start` reads the display mode from one place, both arms.
28
41
 
29
42
  set -uo pipefail
30
43
 
@@ -55,6 +68,8 @@ RFB_PORT=55900
55
68
  WS_PORT=56080
56
69
  VNC_NUM=99
57
70
 
71
+ RESPAWN_STATE="$MAXY_DIR/logs/cdp-respawn.state"
72
+
58
73
  setup() {
59
74
  rm -rf "$ROOT" "$MAXY_DIR"
60
75
  mkdir -p "$ROOT/platform/scripts" "$ROOT/platform/config" "$STATE_DIR" "$FAKE_BIN" "$MAXY_DIR/logs"
@@ -74,11 +89,24 @@ JSON
74
89
  # chromium-binary.path → the stub (a non-snap, executable path).
75
90
  echo "$FAKE_BIN/chromium-stub" > "$ROOT/platform/config/chromium-binary.path"
76
91
 
92
+ # The `start` path resolves the websockify bind posture from this file and
93
+ # hard-exits when it is absent, so the start-path cases need it present.
94
+ echo "bind=127.0.0.1 kind=loopback" > "$ROOT/platform/config/websockify-bind"
95
+
77
96
  : > "$STATE_DIR/ports"
78
97
  echo "$CDP_PORT" > "$STATE_DIR/cdp-port"
79
98
  echo "ready" > "$STATE_DIR/chromium-mode"
80
99
  : > "$STATE_DIR/chromium-calls"
81
100
 
101
+ # One healthy local graphical session by default, so the virtual-mode cases
102
+ # are unaffected by session state and the native cases opt into their own.
103
+ printf '9|yes|no|x11|:1\n' > "$STATE_DIR/sessions"
104
+
105
+ # check_display_collision reads this lock BEFORE kill_stale clears it, so a
106
+ # stale file left by unrelated software on the dev machine would make the
107
+ # start-path cases exit 1 for a reason that is not the code under test.
108
+ rm -f "/tmp/.X${VNC_NUM}-lock"
109
+
82
110
  # Fake ss: LISTEN line iff the requested port is in $STATE_DIR/ports.
83
111
  cat > "$FAKE_BIN/ss" <<'SS'
84
112
  #!/usr/bin/env bash
@@ -98,8 +126,9 @@ SLEEP
98
126
 
99
127
  # Stub Chromium: record the launch — its argv and the DISPLAY it inherited,
100
128
  # so a test can assert HOW Chromium was launched, not just that it was
101
- # (Task 1562 turned the virtual-mode launch headless). In "ready" mode open
102
- # the CDP port.
129
+ # (Task 1562 turned the virtual-mode launch headless; Task 2780 asserts the
130
+ # native launch lands on the discovered session's display). In "ready" mode
131
+ # open the CDP port.
103
132
  cat > "$FAKE_BIN/chromium-stub" <<'STUB'
104
133
  #!/usr/bin/env bash
105
134
  echo "launch DISPLAY=${DISPLAY:-unset} $*" >> "$STATE_DIR/chromium-calls"
@@ -109,7 +138,60 @@ fi
109
138
  exit 0
110
139
  STUB
111
140
 
112
- chmod +x "$FAKE_BIN/ss" "$FAKE_BIN/sleep" "$FAKE_BIN/chromium-stub"
141
+ # Fake loginctl driven by $STATE_DIR/sessions (id|active|remote|type|display).
142
+ # list-sessions prints the systemd column layout so a row-order-dependent
143
+ # reader would still parse it — which is the point: Task 2780's regression is
144
+ # that taking row 1 picked a closing remote tty over the real graphical seat.
145
+ cat > "$FAKE_BIN/loginctl" <<'LOGINCTL'
146
+ #!/usr/bin/env bash
147
+ sessions_file="$STATE_DIR/sessions"
148
+ [ -f "$sessions_file" ] || exit 0
149
+ case "${1:-}" in
150
+ list-sessions)
151
+ while IFS='|' read -r id active remote stype sdisplay; do
152
+ [ -n "$id" ] || continue
153
+ echo "$id 1000 neo seat0 tty2"
154
+ done < "$sessions_file"
155
+ ;;
156
+ show-session)
157
+ want_id="${2:-}"
158
+ prop=""
159
+ shift 2 2>/dev/null || true
160
+ while [ $# -gt 0 ]; do
161
+ if [ "$1" = "-p" ]; then prop="${2:-}"; shift; fi
162
+ shift
163
+ done
164
+ while IFS='|' read -r id active remote stype sdisplay; do
165
+ [ "$id" = "$want_id" ] || continue
166
+ case "$prop" in
167
+ Active) echo "$active" ;;
168
+ Remote) echo "$remote" ;;
169
+ Type) echo "$stype" ;;
170
+ Display) echo "$sdisplay" ;;
171
+ Leader) echo "" ;;
172
+ esac
173
+ done < "$sessions_file"
174
+ ;;
175
+ esac
176
+ exit 0
177
+ LOGINCTL
178
+
179
+ # Display server and websocket bridge: open their ports so the `start` path
180
+ # gets past its two wait_for_port gates without a real X server.
181
+ cat > "$FAKE_BIN/Xtigervnc" <<XVNC
182
+ #!/usr/bin/env bash
183
+ echo "$RFB_PORT" >> "\$STATE_DIR/ports"
184
+ exit 0
185
+ XVNC
186
+
187
+ cat > "$FAKE_BIN/websockify" <<WSK
188
+ #!/usr/bin/env bash
189
+ echo "$WS_PORT" >> "\$STATE_DIR/ports"
190
+ exit 0
191
+ WSK
192
+
193
+ chmod +x "$FAKE_BIN/ss" "$FAKE_BIN/sleep" "$FAKE_BIN/chromium-stub" \
194
+ "$FAKE_BIN/loginctl" "$FAKE_BIN/Xtigervnc" "$FAKE_BIN/websockify"
113
195
  }
114
196
 
115
197
  teardown() {
@@ -126,6 +208,15 @@ run_liveness() {
126
208
  bash "$ROOT/platform/scripts/vnc.sh" cdp-liveness 2>/dev/null
127
209
  }
128
210
 
211
+ # Run the boot path. DISPLAY_MODE is deliberately absent from the environment:
212
+ # no unit file in the fleet exports it, which is the condition under which the
213
+ # split-read this task removes always resolved to "virtual".
214
+ run_start() {
215
+ STATE_DIR="$STATE_DIR" \
216
+ PATH="$FAKE_BIN:$PATH" \
217
+ bash "$ROOT/platform/scripts/vnc.sh" start >/dev/null 2>&1
218
+ }
219
+
129
220
  write_env() {
130
221
  printf 'DISPLAY_MODE=%s\n' "$1" > "$MAXY_DIR/.env"
131
222
  }
@@ -133,6 +224,8 @@ write_env() {
133
224
  chromium_calls() { local n; n=$(grep -c . "$STATE_DIR/chromium-calls" 2>/dev/null); echo "${n:-0}"; }
134
225
  set_ports() { printf '%s\n' "$@" > "$STATE_DIR/ports"; }
135
226
  set_mode() { echo "$1" > "$STATE_DIR/chromium-mode"; }
227
+ set_sessions() { printf '%s\n' "$@" > "$STATE_DIR/sessions"; }
228
+ boot_log() { cat "$MAXY_DIR/logs/vnc-boot.log" 2>/dev/null; }
136
229
 
137
230
  assert() {
138
231
  local desc="$1" cond="$2"
@@ -201,14 +294,20 @@ case_cooldown_retries() {
201
294
  teardown
202
295
  }
203
296
 
204
- # --- Case 5: native modeno-op, no line --------------------------------
205
- case_native_noop() {
206
- echo "=== CASE 5: native DISPLAY_MODE no line, no respawn ==="
297
+ # --- Case 5: native + CDP up a line, naming the mode -------------------
298
+ # Before Task 2780 this case asserted the opposite: native emitted NOTHING and
299
+ # supervised nothing. That silence is the defect fourteen hours of no
300
+ # supervision and fourteen hours of healthy supervision produced identical
301
+ # journals — so the assertion is inverted rather than deleted.
302
+ case_native_reachable() {
303
+ echo "=== CASE 5: native + CDP up → reachable=true, mode named, no respawn ==="
207
304
  setup; write_env native
208
- set_ports "$RFB_PORT" # display up, CDP down — normal idle in native
305
+ set_ports "$CDP_PORT" "$RFB_PORT"
209
306
  out="$(run_liveness)"
210
- assert "emits no op= line" "$([ -z "$(echo "$out" | grep -E 'op=(cdp-liveness|chromium-respawn)')" ] && echo 1 || echo 0)"
211
- assert "zero chromium launches" "$([ "$(chromium_calls)" -eq 0 ] && echo 1 || echo 0)"
307
+ assert "emits display-mode=native" "$(echo "$out" | grep -qE 'op=cdp-liveness .*display-mode=native' && echo 1 || echo 0)"
308
+ assert "emits reachable=true" "$(echo "$out" | grep -qE 'op=cdp-liveness .*reachable=true' && echo 1 || echo 0)"
309
+ assert "no chromium-respawn line" "$(echo "$out" | grep -q 'op=chromium-respawn' && echo 0 || echo 1)"
310
+ assert "zero chromium launches" "$([ "$(chromium_calls)" -eq 0 ] && echo 1 || echo 0)"
212
311
  teardown
213
312
  }
214
313
 
@@ -233,12 +332,164 @@ case_respawn_is_headed() {
233
332
  teardown
234
333
  }
235
334
 
335
+ # --- Case 7: native + CDP down + a graphical session → native respawn ----
336
+ case_native_respawns() {
337
+ echo "=== CASE 7: native + CDP down + graphical session → one native respawn ==="
338
+ setup; write_env native
339
+ set_sessions "9|yes|no|x11|:1"
340
+ set_ports "$RFB_PORT" # CDP down
341
+ set_mode ready
342
+ out="$(run_liveness)"
343
+ assert "emits reachable=false naming native" "$(echo "$out" | grep -qE 'op=cdp-liveness .*display-mode=native .*reachable=false' && echo 1 || echo 0)"
344
+ assert "emits chromium-respawn ready" "$(echo "$out" | grep -qE 'op=chromium-respawn .*display-mode=native .*outcome=ready' && echo 1 || echo 0)"
345
+ assert "exactly one chromium launch" "$([ "$(chromium_calls)" -eq 1 ] && echo 1 || echo 0)"
346
+ assert "launch lands on the session display" "$(grep -q "DISPLAY=:1 " "$STATE_DIR/chromium-calls" && echo 1 || echo 0)"
347
+ teardown
348
+ }
349
+
350
+ # --- Case 8: native + no local graphical session → decline, no launch ----
351
+ case_native_declines_without_session() {
352
+ echo "=== CASE 8: native + no active local graphical session → decline ==="
353
+ setup; write_env native
354
+ set_sessions "3|yes|yes|tty|" "4|no|no|x11|:1" # remote, then inactive
355
+ set_ports "$RFB_PORT"
356
+ set_mode ready
357
+ out="$(run_liveness)"
358
+ assert "still emits reachable=false" "$(echo "$out" | grep -qE 'op=cdp-liveness .*display-mode=native .*reachable=false' && echo 1 || echo 0)"
359
+ assert "emits outcome=declined" "$(echo "$out" | grep -qE 'op=chromium-respawn .*outcome=declined reason=no-graphical-session' && echo 1 || echo 0)"
360
+ assert "zero chromium launches" "$([ "$(chromium_calls)" -eq 0 ] && echo 1 || echo 0)"
361
+ assert "no respawn state written" "$([ ! -f "$RESPAWN_STATE" ] && echo 1 || echo 0)"
362
+ teardown
363
+ }
364
+
365
+ # --- Case 9: session chosen by evidence, not by row order ----------------
366
+ # On the laptop the first row is a remote tty in state closing and the real
367
+ # graphical session is last. Taking row 1 gave an empty Display, which the old
368
+ # code substituted with :0 — right screen by accident on that box, wrong or
369
+ # absent screen on any other.
370
+ #
371
+ # Row 7 is the derived case: it satisfies all three selection criteria but
372
+ # names no Display, so it carries no launch vector. Accepting it would put the
373
+ # guess back, just one row later.
374
+ case_native_session_selection() {
375
+ echo "=== CASE 9: graphical session is the last row → chosen over four decoys ==="
376
+ setup; write_env native
377
+ set_sessions "1|no|yes|tty|" "2|yes|yes|tty|" "5|yes|no|tty|" "7|yes|no|x11|" "9|yes|no|x11|:1"
378
+ set_ports "$RFB_PORT"
379
+ set_mode ready
380
+ run_liveness >/dev/null
381
+ local call; call="$(cat "$STATE_DIR/chromium-calls")"
382
+ assert "launch carries the graphical session display" "$(echo "$call" | grep -q "DISPLAY=:1 " && echo 1 || echo 0)"
383
+ assert "launch never falls back to :0" "$(echo "$call" | grep -q "DISPLAY=:0 " && echo 0 || echo 1)"
384
+ teardown
385
+ }
386
+
387
+ # --- Case 10: `start` reads the display mode from one place --------------
388
+ # The defect: resolve_display_mode() read the brand .env while the start case
389
+ # read the DISPLAY_MODE env var, which no unit file exports. Both arms run,
390
+ # because the bug was one arm being unreachable.
391
+ case_start_mode_single_authority() {
392
+ echo "=== CASE 10: vnc.sh start resolves the mode from one place, both arms ==="
393
+ setup; write_env native
394
+ set_sessions "9|yes|no|x11|:1"
395
+ run_start
396
+ assert "native arm logs mode=native" "$(boot_log | grep -q 'mode=native' && echo 1 || echo 0)"
397
+ assert "native arm boots no Chromium" "$([ "$(chromium_calls)" -eq 0 ] && echo 1 || echo 0)"
398
+ teardown
399
+
400
+ setup; write_env virtual
401
+ run_start
402
+ assert "virtual arm logs mode=virtual" "$(boot_log | grep -q 'mode=virtual' && echo 1 || echo 0)"
403
+ assert "virtual arm boots Chromium" "$([ "$(chromium_calls)" -ge 1 ] && echo 1 || echo 0)"
404
+ teardown
405
+ }
406
+
407
+ # --- Case 11: the on-demand path carries the same refusal ----------------
408
+ # `start-chrome-native` is what ensureCdp() shells for a native transport from
409
+ # the browser-pane route. It is a SEPARATE entry point from cdp-liveness and
410
+ # reaches start_chrome_native's own guard, which the liveness cases never do
411
+ # because cdp_liveness returns at its precondition first. ensureCdp runs this
412
+ # through execFileSync, which throws on a non-zero exit, so the exit status is
413
+ # the contract that turns a refusal into a reported failure rather than a
414
+ # silent success.
415
+ case_start_chrome_native_subcommand() {
416
+ echo "=== CASE 11: start-chrome-native refuses without a session, launches with one ==="
417
+ setup; write_env native
418
+ set_sessions "3|yes|yes|tty|" "4|no|no|x11|:1" # remote, then inactive
419
+ set_mode ready
420
+ out="$(STATE_DIR="$STATE_DIR" PATH="$FAKE_BIN:$PATH" bash "$ROOT/platform/scripts/vnc.sh" start-chrome-native 2>/dev/null)"
421
+ local rc=$?
422
+ assert "declines under op=chromium-start" "$(echo "$out" | grep -qE 'op=chromium-start .*outcome=declined reason=no-graphical-session' && echo 1 || echo 0)"
423
+ assert "exits non-zero so ensureCdp sees it" "$([ "$rc" -ne 0 ] && echo 1 || echo 0)"
424
+ assert "zero chromium launches" "$([ "$(chromium_calls)" -eq 0 ] && echo 1 || echo 0)"
425
+ teardown
426
+
427
+ setup; write_env native
428
+ set_sessions "9|yes|no|x11|:1"
429
+ set_mode ready
430
+ out="$(STATE_DIR="$STATE_DIR" PATH="$FAKE_BIN:$PATH" bash "$ROOT/platform/scripts/vnc.sh" start-chrome-native 2>/dev/null)"
431
+ assert "launches under op=chromium-start ready" "$(echo "$out" | grep -qE 'op=chromium-start display-mode=native mode=x11 .*outcome=ready' && echo 1 || echo 0)"
432
+ assert "launch lands on the session display" "$(grep -q "DISPLAY=:1 " "$STATE_DIR/chromium-calls" && echo 1 || echo 0)"
433
+ teardown
434
+ }
435
+
436
+ # --- Case 12: the cap and cooldown apply to native unchanged -------------
437
+ # Case 3 proves this for virtual. Native shares the state file, the cap and the
438
+ # cooldown, so a native box whose Chromium will not launch must back off the
439
+ # same way rather than relaunching every cycle.
440
+ case_native_backoff_no_hotloop() {
441
+ echo "=== CASE 12: native repeated launch failure → respawn capped at MAX ==="
442
+ setup; write_env native
443
+ set_sessions "9|yes|no|x11|:1" # session present, so it is not a decline
444
+ set_ports "$RFB_PORT" # CDP stays down
445
+ set_mode fail # every launch fails to open CDP
446
+ local i
447
+ for i in 1 2 3 4 5; do
448
+ RESPAWN_MAX_FAILS=3 RESPAWN_COOLDOWN_SECS=300 run_liveness >/dev/null
449
+ done
450
+ assert "native respawn capped at 3 over 5 cycles" "$([ "$(chromium_calls)" -eq 3 ] && echo 1 || echo 0)"
451
+ assert "native failure writes the respawn state" "$([ -f "$RESPAWN_STATE" ] && echo 1 || echo 0)"
452
+ teardown
453
+ }
454
+
455
+ # --- Case 13: the per-cycle path writes nothing to vnc-boot.log ----------
456
+ # vnc-boot.log is NOT one of logs-rotate.sh's targets, so nothing bounds it.
457
+ # vnc.sh already suppresses its one per-invocation line on the cdp-liveness
458
+ # path for exactly this reason. Native session discovery runs on that path
459
+ # every 30s, so its per-session detail must not land in that file either — a
460
+ # native box with no seat would otherwise grow it forever.
461
+ case_liveness_does_not_grow_boot_log() {
462
+ echo "=== CASE 13: cdp-liveness writes nothing to the unrotated vnc-boot.log ==="
463
+ setup; write_env native
464
+ set_sessions "3|yes|yes|tty|" "4|no|no|x11|:1" # no match → the chattiest path
465
+ set_ports "$RFB_PORT"
466
+ local i
467
+ for i in 1 2 3; do run_liveness >/dev/null; done
468
+ local lines; lines="$(boot_log | grep -c . 2>/dev/null)"; lines="${lines:-0}"
469
+ assert "three decline cycles add no vnc-boot.log lines" "$([ "$lines" -eq 0 ] && echo 1 || echo 0)"
470
+ teardown
471
+
472
+ # The same detail IS kept on the launch-attempt path, which is event-driven.
473
+ setup; write_env native
474
+ set_sessions "3|yes|yes|tty|" "4|no|no|x11|:1"
475
+ STATE_DIR="$STATE_DIR" PATH="$FAKE_BIN:$PATH" bash "$ROOT/platform/scripts/vnc.sh" start-chrome-native >/dev/null 2>&1
476
+ assert "start-chrome-native still records why it refused" "$(boot_log | grep -q 'no-graphical-session' && echo 1 || echo 0)"
477
+ teardown
478
+ }
479
+
236
480
  case_reachable_noop
237
481
  case_down_respawns_ready
238
482
  case_backoff_no_hotloop
239
483
  case_cooldown_retries
240
- case_native_noop
484
+ case_native_reachable
241
485
  case_respawn_is_headed
486
+ case_native_respawns
487
+ case_native_declines_without_session
488
+ case_native_session_selection
489
+ case_start_mode_single_authority
490
+ case_start_chrome_native_subcommand
491
+ case_native_backoff_no_hotloop
492
+ case_liveness_does_not_grow_boot_log
242
493
 
243
494
  echo ""
244
495
  echo "==================================="