verikun 0.25.0 → 0.26.0-rc.1

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.
@@ -141,7 +141,10 @@ banner, the retry path, dark theme, a layout that breaks at accessibility text s
141
141
  you reset it, so don't leave someone's phone in airplane mode.
142
142
 
143
143
  - `vk device prep [--dry-run] [--revert]` — set a **test** device up once, stickily:
144
- `animations=off stay-awake=on screen-timeout=max dnd=on doze=off`.
144
+ `animations=off stay-awake=off screen-timeout=1m dnd=on doze=off`. The display then sleeps by
145
+ itself a minute after the last command and is woken by the next one; `--no-sleep-when-idle`
146
+ keeps it lit for good (`stay-awake=on screen-timeout=max`), which is what a device with a
147
+ PIN/pattern lock needs, since verikun can only clear a *swipe* lock.
145
148
 
146
149
  Unlike `device set`, prep **survives the run** and is undone only by `--revert`. A physical
147
150
  device must be named (`--device <serial>`) — that requirement is deliberate, so prep can
@@ -394,7 +397,8 @@ vk ai onboarding.md --timeout 5m # tighten the run timeout (default 15m)
394
397
  (`--max-cost-usd`) or the wall-clock passes **15m** (`--timeout`), so a runaway
395
398
  compile/repair loop can't spend or hang without limit. The ceiling is **per test, not per
396
399
  suite** — `vk suite` gives each `*.md` its own fresh budget, so 20 tests at the default can
397
- reach $60; there is no suite-wide cap, so lower the per-test figure instead. A model is only
400
+ reach $60; lower the per-test figure, or set `vk suite --max-suite-cost-usd <n>` for an
401
+ aggregate cap (off by default; stops the suite at exit `1`). A model is only
398
402
  ever called to **compile** (once, on a cache miss) or to **repair** (≤3 per failing step);
399
403
  replay is always $0, and every non-`ai` command is $0 always. Full mechanism, the estimate
400
404
  formula and the cache multipliers: <https://ddikman.github.io/verikun/reference/cost/>.
@@ -434,6 +438,28 @@ vk suite tests/ --app com.example.app # reset app data between tests
434
438
  are **not** counted as failures. So `3` = fix the machine and rerun; `1` = a real
435
439
  regression to investigate.
436
440
 
441
+ ### Across several devices
442
+
443
+ Suite time is the **sum** of its tests on one device. Given a pool, the suite becomes a
444
+ work queue instead — every device takes the next test as it frees up:
445
+
446
+ ```sh
447
+ vk suite tests/ --app com.example.app --devices emulator-5554,emulator-5556
448
+ vk suite tests/ --app com.example.app --server "$VERIKUN_SERVER" # a pooled server
449
+ vk suite tests/ --app com.example.app --servers http://a:8391,http://b:8391
450
+ ```
451
+
452
+ - A `vk server --devices all` holds several devices behind one URL; a plain `--server`
453
+ suite reads its capacity and sizes itself. Nothing else about the command changes.
454
+ - **File order stops sequencing tests** — they must be independent. Ordering becomes
455
+ longest-first, learned from the previous run's `index.json`.
456
+ - Each row records **which device ran it**, and the manifest splits
457
+ `totals.wallClockMs` (how long the gate took) from `totals.durationMs` (device-seconds).
458
+ - `--concurrency N` caps how many run at once — more devices on one host can thrash it.
459
+ `--max-suite-cost-usd N` stops the suite once total model spend crosses it (exit `1`).
460
+ - A device that breaks retires; its tests move to the others. Exit `3` only when all are gone.
461
+ - `--ensure-device` is refused with `--devices` — start the pool with `vk devices start`.
462
+
437
463
  ## Drive a remote device (--server)
438
464
 
439
465
  If the device is attached to another machine running `vk server`, point
@@ -447,11 +473,17 @@ vk install ./app-debug.apk --server "$VERIKUN_SERVER" # server needs --allow-i
447
473
  vk suite tests/ --app com.example.app --server "$VERIKUN_SERVER"
448
474
  ```
449
475
 
450
- A wrong URL/key fails fast with exit 3; `409` means another run holds the
451
- device; `503` means the server has no device attached — boot one (below). To
452
- expose a device from THIS machine: `vk server --allow-install`
476
+ A wrong URL/key fails fast with exit 3; `409` means every device is already
477
+ leased by another run; `503` means the server has no device attached — boot one
478
+ (below). To expose a device from THIS machine: `vk server --allow-install`
453
479
  (add `--bind <addr>` to leave loopback; auth key auto-generates if unset).
454
480
 
481
+ `vk server --devices all` (or `all-android` / `all-ios` / a serial list) serves a **pool**
482
+ from one address. Each run leases one device for its whole life, so a run's steps and
483
+ repairs always land on the same phone. `vk install --server` then installs on every device;
484
+ `vk devices start|restart|stop --server` is refused (`403`) — a pool has no single device
485
+ to act on.
486
+
455
487
  **If you see `[verikun] server moved device: A → B` on stderr**, the server left a
456
488
  device that failed and is now on another one. What that means depends on the line:
457
489
 
@@ -463,7 +495,9 @@ device that failed and is now on another one. What that means depends on the lin
463
495
  flow again from the top if you want it on B.
464
496
 
465
497
  The server rules the bad device out until it is power-cycled;
466
- `vk devices --server <url>` shows why in its `NOTE` column.
498
+ `vk devices --server <url>` shows why in its `NOTE` column. On a pool the replacement
499
+ joins the pool, so capacity holds — and the last device is never shed, so its own error
500
+ keeps reaching you rather than a bare "no device attached".
467
501
 
468
502
  ## The device is missing or wedged
469
503
 
@@ -549,6 +583,8 @@ owns the redaction and the review-first flow.
549
583
  verikun detects this, wakes the device and clears a *swipe* lock automatically; on a
550
584
  PIN/pattern/password it exits **3** naming the lock rather than returning that dump.
551
585
  Tell the user to remove the lock in Settings > Security — verikun never asks for a PIN.
586
+ Taps, swipes, typing and screenshots wake it the same way: a prepped display sleeps after a
587
+ minute idle, and an injected tap on a sleeping screen would otherwise do nothing and exit `0`.
552
588
  - **Ambiguous selector → exit 2**, never a random tap. `vk` prints the candidate
553
589
  matches; add `--index N` or use a more specific selector.
554
590
  - **Indexes are per-snapshot.** `vk tap 3` taps `[3]` from the *latest* dump;
package/CHANGELOG.md CHANGED
@@ -6,6 +6,70 @@ All notable changes to this project are documented here. The format is based on
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ### Changed
10
+ - **`VERIKUN_CLAIM_TTL_MIN`** now also paces a parallel suite's claim heartbeat — a quarter of
11
+ the window, capped at 60s — so a short TTL no longer races it.
12
+
13
+ ## [0.26.0] - 2026-08-24
14
+
15
+ ### Added
16
+ - **`vk suite --devices a,b` / `--servers u1,u2`**: run tests across a device pool, next free
17
+ device takes the next test. One merged report. ([#39])
18
+ - **`vk suite --server`**: sizes itself automatically from a pooled server's capacity — one URL,
19
+ one secret, unchanged CI line. ([#39])
20
+ - **`vk server --devices all | all-android | all-ios | a,b`**: serve several devices from one
21
+ address, one lease per run. ([#39])
22
+ - **`vk suite --devices all | all-android | all-ios`**: same spelling as `vk server --devices`. ([#39])
23
+ - **`vk suite --concurrency n`**: cap how many devices run at once, below the pool's size. ([#39])
24
+ - **`vk suite --max-suite-cost-usd n`**: stop the suite once total model spend crosses it
25
+ (exit `1`). Off by default. ([#39])
26
+ - **`vk ai --reset-app <id>`**: clear (iOS: force-stop) the app before the first step, on the run's
27
+ own device.
28
+ - **`VERIKUN_LANE`**: moves the active run to `./.verikun/run-<lane>/` so concurrent tests in one
29
+ working directory don't delete each other's state.
30
+ - **`POST /v1/lease`** and `capacity` / `devices` on `/v1/health`: which device a run token holds,
31
+ and how many the server has.
32
+
33
+ ### Changed
34
+ - **Suite manifest**: adds `totals.wallClockMs`, `concurrency` and a per-test `device`.
35
+ `totals.durationMs` is unchanged but is now labelled device time. `schemaVersion` stays `1`.
36
+ - **`vk install --server`** installs on **every** device of a pooled server, not one.
37
+ - **Release workflow**: a prerelease tag takes its GitHub release notes from the version it is a candidate for (`v1.0.0-rc.1` → `## [1.0.0]`).
38
+ - **`vk suite --devices`**: file order no longer sequences tests, and longest-first ordering is
39
+ taken from the previous run's manifest. A serial suite is unchanged. ([#39])
40
+ - **`vk server --devices`**: `/v1/devices/{start,restart,stop}` answer `403` on a pool — there is
41
+ no single device to act on. `--ensure-device` is likewise refused with `--devices`.
42
+ - **`vk suite --devices` with `--server`** is a usage error (exit `2`): it would have tested local
43
+ devices and reported green.
44
+ - **`vk suite --servers u1,u2`**: opens one lane per device each server has, not one per URL.
45
+ - **`vk server`**: a lease is broken only when another run needs that device, so a paused run
46
+ keeps its own phone.
47
+ - **`--json` errors** carry `errorKind`, the error's class, so a caller need not match on message
48
+ text.
49
+ - **`vk server --devices all`** and failover prefer virtual devices, so neither enlists an attached
50
+ phone unasked.
51
+ - **`vk server` failover on a pool**: a failed device is quarantined and a healthy one takes its
52
+ place, so capacity holds. ([#39], [#99])
53
+
54
+ ### Fixed
55
+ - **`--server` runs no longer fail with `fetch failed`** when a step follows a pause longer
56
+ than 5s, such as a cold compile.
57
+ - **`--server` screenshots and failure evidence** are no longer corrupted in the archived report.
58
+
59
+ [#39]: https://github.com/ddikman/verikun/issues/39
60
+
61
+ ## [0.25.1] - 2026-08-21
62
+
63
+ ### Changed
64
+ - **`vk device prep`**: gives the display a 1-minute timeout instead of keeping it lit forever; `--no-sleep-when-idle` keeps the old behaviour. ([#101])
65
+ - **`vk batch|ai|suite`**: no longer switch a prepped device's display off at teardown — it now sleeps by itself.
66
+ - **`vk tap|type|key|swipe|screenshot`**: wake a sleeping display first; an injected tap on a dozing screen did nothing and exited `0`.
67
+
68
+ ### Added
69
+ - **`vk device prep`**: warns when a device that will now sleep is behind a PIN/pattern lock.
70
+
71
+ [#101]: https://github.com/ddikman/verikun/issues/101
72
+
9
73
  ## [0.25.0] - 2026-08-21
10
74
 
11
75
  ### Added
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  - **Puppeteer for native mobile** — a thin wrapper over native Android and iOS automation runners with zero runtime dependencies.
9
9
  - **Natural-language tests** — `vk ai <file>`: runs plain-English tests, compiled once and replayed model-free (~$0), calling a model only to self-heal a drifted step. [What that costs](https://ddikman.github.io/verikun/reference/cost/), and how the `--max-cost-usd` ceiling bounds it.
10
10
  - **Self-improving** — the agent runner will provide prescriptive improvements to existing scripts to help stabilise flakiness for future runs.
11
- - **CI-ready** — `vk suite` runs a folder of tests as one gated pass/fail run; `vk server` exposes a real device over an authenticated tunnel so a disposable CI runner (no phone attached) can still drive it, and moves to another attached device if that one goes bad.
11
+ - **CI-ready** — `vk suite` runs a folder of tests as one gated pass/fail run, across one device or a whole pool of them; `vk server` exposes real devices over an authenticated tunnel so a disposable CI runner (no phone attached) can still drive them, and swaps out any that goes bad.
12
12
 
13
13
  ```
14
14
  $ vk ui
@@ -38,7 +38,7 @@ The package also carries the agent [`SKILL.md`](.claude/skills/verikun/SKILL.md)
38
38
 
39
39
  ```sh
40
40
  vk doctor # check adb/device (read-only — never changes anything)
41
- vk device prep --device <id> # set a TEST device up once: animations off, stays awake
41
+ vk device prep --device <id> # set a TEST device up once: animations off, sane display timeout
42
42
  vk devices # list attached devices
43
43
  vk ui # semantic snapshot of the current screen
44
44
  vk tap @login_button # tap by resource-id
@@ -170,6 +170,13 @@ function createRemoteBackend(opts, health) {
170
170
  };
171
171
  return {
172
172
  exec: (command, positionals, flags) => execRaw({ command, positionals, flags }, true),
173
+ async lease() {
174
+ // Feature-detect on a FIELD, never on the version: `capacity` and /v1/lease landed
175
+ // together, and a client cannot otherwise tell "old server" from "new server".
176
+ if (health.capacity === undefined)
177
+ return null;
178
+ return t.postJson('/v1/lease', {}, HEALTH_TIMEOUT_MS);
179
+ },
173
180
  async getElements() {
174
181
  const res = await t.postJson('/v1/elements', {}, ELEMENTS_TIMEOUT_MS);
175
182
  return res.elements;