hkblockchaintechnology commited on
Commit
ec47130
·
verified ·
1 Parent(s): e2f048d

Card: 2.0 - measured test counts, gallery coverage, watchdog and audit

Browse files
Files changed (1) hide show
  1. README.md +32 -18
README.md CHANGED
@@ -94,7 +94,7 @@ X server. First the suite, headless:
94
  ```bash
95
  python -m pip install -e ".[desktop,ocr,dev]"
96
  pytest tests -q
97
- # 227 passed, 2 skipped in 18.7s (that run was 0.3.0; 2.0 has grown this to 284)
98
  ```
99
 
100
  The two skips are the live-desktop tests. Give them a display and they run for real:
@@ -266,7 +266,7 @@ open problem: it is reliable on a clean screenshot and unreliable on a busy live
266
  `warning: no text was found on screen, so the index is 96 numbered grid cells and the
267
  agent is choosing blind` — instead of silently guessing.
268
 
269
- **284 tests pass**, including real OCR over a real image and (opt-in) live-desktop tests
270
  that click a real button.
271
 
272
  ## Verified on real Windows
@@ -314,7 +314,7 @@ the harness itself, installed into site-packages
314
 
315
  None of the three failures in the first row is a harness defect: two are
316
  `ModuleNotFoundError: numpy` and the third is the guard bug documented below. With the
317
- OCR engine installed, the same suite exits **0**. (Those Windows counts predate `trace.py` and 2.0; the harness suite has since grown to 284 tests.)
318
 
319
  **The emulated-OCR caveat.** onnxruntime requires AVX2, and QEMU's software emulation of
320
  AVX2 is roughly two orders of magnitude slower than native. A suite that finishes in 17
@@ -340,7 +340,7 @@ exactly the kind of thing that only surfaces on a machine without an OCR engine.
340
 
341
  ## The test suite, in full
342
 
343
- `pytest tests` collects **284 tests**. 282 run headless — no display, no network, no
344
  weights. The last 2 are the opt-in live-desktop tests, skipped unless
345
  `TINY_COMPUTER_AGENT_LIVE_TEST=1`. On a box without PyGObject, two of the 282 *fail* rather
346
  than skip: they assert the AT-SPI reader is reachable, and that is the honest outcome.
@@ -356,19 +356,22 @@ than skip: they assert the AT-SPI reader is reachable, and that is the honest ou
356
  | `tests/test_verify.py` | 7 | success is only claimed when a verifier can actually see it |
357
  | `tests/test_safety.py` | 11 | deny lists, the kill switch, the blind-grid-click guard |
358
  | `tests/test_grid_fallback.py` | 11 | the fallback index announces itself instead of guessing |
359
- | `tests/test_desktop.py` | 10 | display detection, the preflight checks, `doctor` |
360
- | `tests/test_cli.py` | 16 | the command line: `--doctor`, `--image`, `--live`, and the 2.0 `skills` / `batch` subcommands |
361
  | `tests/test_trace.py` | 28 | traces: a run recorded with no pixels, replayed against another brain, and scored against ground truth |
362
  | `tests/test_models.py` | 7 | the model backends: lazy loading, device choice, honest refusals |
363
  | `tests/test_api_surface.py` | 4 | the public API is a promise: everything advertised is importable, and nothing public is left out |
364
  | `tests/test_decoding.py` | 24 | the mask, the answer space, the retry ladder, the vote - and that an echo is refused |
365
- | `tests/test_accessibility.py` | 26 | role filtering, the coordinate contract, the fallback chain, and real AT-SPI |
366
  | `tests/test_diff.py` | 8 | what changed between two frames: added, removed, moved, and the verifier that remembers |
367
  | `tests/test_stepwise.py` | 11 | begin / step / pause / resume, and that it equals the batch loop |
368
  | `tests/test_ocr_guard.py` | 4 | the OCR guard really skips with no engine - the guard that never fired |
369
- | `tests/test_gates.py` | 8 | the operator's yes: whitelists, ask-once gates, and a refusal that is a step |
370
  | `tests/test_skills.py` | 17 | only a verified run becomes a skill; re-grounding by label; aiming at nothing raises |
371
  | `tests/test_runner.py` | 10 | a queue, a JSONL resume file, and a report counts what was verified |
 
 
 
372
  | `tests/test_live_desktop.py` | 2 | **needs a display, opt-in**: OCR finds a real button at the pixels it was drawn at, and a real click makes the app react |
373
 
374
  ```bash
@@ -383,7 +386,7 @@ TINY_COMPUTER_AGENT_LIVE_TEST=1 pytest tests -q # + the 2 live-desktop tests, o
383
  pip install -e ".[ocr]" # labels from pixels (RapidOCR: no system binary)
384
  pip install -e ".[desktop,ocr]" # + real capture and real input
385
  pip install -e ".[vision,ocr]" # + the tiny model brains
386
- pytest # 284 tests, no display or network needed
387
  ```
388
 
389
  The accessibility detector needs system packages rather than an extra:
@@ -499,6 +502,8 @@ this: an answer file with non-canonical XML namespaces is **silently ignored** b
499
  | `skills.py` | **2.0** - Skills: a *verified* run written down once, replayed by `SkillBrain` with no model. Labels, never coordinates |
500
  | `gates.py` | **2.0** - Approval gates: `AllowOnlyLabels`, `InteractiveGate` (yes / no / always / never), `AllOf` / `AnyOf`. A refusal is a step |
501
  | `runner.py` | **2.0** - `TaskRunner`: a queue of goals, a JSONL resume file, and a `RunReport` that counts what was *verified* |
 
 
502
  | `showcase.py` | The capability gallery: one real screenshot per capability, checked against the public API |
503
  | `measure_vlm.py` | Measures the four ways to ask a model, on a real screen, and prints the table |
504
  | `evaluate_daily.py` | A day's tasks against a real app, verified by the app's own log |
@@ -549,9 +554,10 @@ That click was found **without reading a single pixel**: the window's own status
549
  reads `last action: Save` afterwards, and the app wrote `Save` to its marker file.
550
  `--detector best` tries the tree first, then OCR, then the numbered grid.
551
 
552
- **Honest limits.** AT-SPI is Linux-only here; **UI Automation is not implemented**, and
553
- `accessibility_available("uia")` says exactly that rather than pretending - so an agent
554
- on Windows keeps using OCR. Tk barely publishes a tree and a canvas publishes none,
 
555
  which is why this is a detector and not a replacement.
556
 
557
  ## Can it do a day's work?
@@ -605,7 +611,7 @@ eleven tasks are a sample, not a survey.
605
 
606
  ## Capability gallery
607
 
608
- **74 capabilities, one screenshot each - and 173 of the package's 180 pre-2.0 public callables (functions, methods, classes and protocols) appear in at least one of them**, together with 10 of its public constants. The 2.0 additions are not pictured yet: **84 new public callables** (skills, approval gates, the batch runner and the structural diff) plus four new CLI entry points. The counts are read off `gallery/index.json`, which records what each picture shows.
609
 
610
  Nothing here is a mock-up. Each picture is produced by [`showcase.py`](showcase.py): a command or a call is run for real, and its actual output - or the real desktop it acted on - is what you see. The desktop shots are real screen captures on a real X server (Xvfb, 1280x800), including a real mouse click verified by the target application's own reaction.
611
 
@@ -1233,15 +1239,15 @@ success.
1233
  **Works:** real capture, a real OCR index with coordinates that land on the right pixel,
1234
  a real click an app reacts to, verified success, the closed vocabulary, the policy gates,
1235
  the no-progress guard, echo detection, the doctor, the CLI, portable traces that score a brain's choices offline, skills learned from verified runs,
1236
- a resumable task runner, operator approval gates, 284 tests, a 256M VLM that
1237
  reads a button label from pixels on a clean screenshot — and the same suite passing inside
1238
  a real Windows Server 2022 guest with no KVM (109 passed, exit 0, with the OCR-inference
1239
  tests excluded as impractically slow under emulation).
1240
 
1241
  **Does not work yet:** reliability on a *live* screen. The 256M VLM echoed the prompt
1242
- there; the 0.5B text planner picks wrong actions; the accessibility-tree detector is not
1243
- implemented, so labels come from OCR only; and the harness still trusts a model's `done`
1244
- when no verifier is given.
1245
 
1246
  ## Roadmap
1247
 
@@ -1266,7 +1272,15 @@ when no verifier is given.
1266
  - [x] **2.0** Operator approval gates - a label whitelist, or ask before every action
1267
  - [x] **2.0** A resumable task queue with a report, and structural verification of "it worked"
1268
  - [x] **2.0** `skills` and `batch` subcommands, and an example queue at `tasks/day.json`
1269
- - [ ] A gallery run that pictures the 2.0 additions: the 84 new public callables have no screenshot yet
 
 
 
 
 
 
 
 
1270
  - [ ] **Verify UI Automation** (Windows) against a real Windows desktop. The reader and the
1271
  detector are implemented and unit-tested against a synthetic control tree, and
1272
  `accessibility_available("uia")` reports the truth on any machine - but no Windows
 
94
  ```bash
95
  python -m pip install -e ".[desktop,ocr,dev]"
96
  pytest tests -q
97
+ # 227 passed, 2 skipped in 18.7s (that run was 0.3.0; 2.0 has grown this to 327)
98
  ```
99
 
100
  The two skips are the live-desktop tests. Give them a display and they run for real:
 
266
  `warning: no text was found on screen, so the index is 96 numbered grid cells and the
267
  agent is choosing blind` — instead of silently guessing.
268
 
269
+ **327 tests collect** - 315 pass, 12 skip for want of a display or an AT-SPI typelib - including real OCR over a real image and (opt-in) live-desktop tests
270
  that click a real button.
271
 
272
  ## Verified on real Windows
 
314
 
315
  None of the three failures in the first row is a harness defect: two are
316
  `ModuleNotFoundError: numpy` and the third is the guard bug documented below. With the
317
+ OCR engine installed, the same suite exits **0**. (Those Windows counts predate `trace.py` and 2.0; the harness suite has since grown to 327 tests.)
318
 
319
  **The emulated-OCR caveat.** onnxruntime requires AVX2, and QEMU's software emulation of
320
  AVX2 is roughly two orders of magnitude slower than native. A suite that finishes in 17
 
340
 
341
  ## The test suite, in full
342
 
343
+ `pytest tests` collects **327 tests**. 325 run headless — no display, no network, no
344
  weights. The last 2 are the opt-in live-desktop tests, skipped unless
345
  `TINY_COMPUTER_AGENT_LIVE_TEST=1`. On a box without PyGObject, two of the 282 *fail* rather
346
  than skip: they assert the AT-SPI reader is reachable, and that is the honest outcome.
 
356
  | `tests/test_verify.py` | 7 | success is only claimed when a verifier can actually see it |
357
  | `tests/test_safety.py` | 11 | deny lists, the kill switch, the blind-grid-click guard |
358
  | `tests/test_grid_fallback.py` | 11 | the fallback index announces itself instead of guessing |
359
+ | `tests/test_desktop.py` | 12 | display detection, the preflight checks, `doctor` |
360
+ | `tests/test_cli.py` | 22 | the command line: `--doctor`, `--image`, `--live`, and the 2.0 `skills` / `batch` subcommands |
361
  | `tests/test_trace.py` | 28 | traces: a run recorded with no pixels, replayed against another brain, and scored against ground truth |
362
  | `tests/test_models.py` | 7 | the model backends: lazy loading, device choice, honest refusals |
363
  | `tests/test_api_surface.py` | 4 | the public API is a promise: everything advertised is importable, and nothing public is left out |
364
  | `tests/test_decoding.py` | 24 | the mask, the answer space, the retry ladder, the vote - and that an echo is refused |
365
+ | `tests/test_accessibility.py` | 27 | role filtering, the coordinate contract, the fallback chain, and real AT-SPI |
366
  | `tests/test_diff.py` | 8 | what changed between two frames: added, removed, moved, and the verifier that remembers |
367
  | `tests/test_stepwise.py` | 11 | begin / step / pause / resume, and that it equals the batch loop |
368
  | `tests/test_ocr_guard.py` | 4 | the OCR guard really skips with no engine - the guard that never fired |
369
+ | `tests/test_gates.py` | 14 | the operator's yes: whitelists, ask-once gates, and a refusal that is a step |
370
  | `tests/test_skills.py` | 17 | only a verified run becomes a skill; re-grounding by label; aiming at nothing raises |
371
  | `tests/test_runner.py` | 10 | a queue, a JSONL resume file, and a report counts what was verified |
372
+ | `tests/test_watchdog.py` | 12 | a hung call becomes a named step instead of a stall - and the thread it leaves behind is admitted |
373
+ | `tests/test_audit.py` | 12 | the chain verifies, and editing, deleting or reordering a line is caught by number |
374
+ | `tests/test_atspi_guard.py` | 4 | the AT-SPI guard really skips without the typelib - the same trap as the OCR guard |
375
  | `tests/test_live_desktop.py` | 2 | **needs a display, opt-in**: OCR finds a real button at the pixels it was drawn at, and a real click makes the app react |
376
 
377
  ```bash
 
386
  pip install -e ".[ocr]" # labels from pixels (RapidOCR: no system binary)
387
  pip install -e ".[desktop,ocr]" # + real capture and real input
388
  pip install -e ".[vision,ocr]" # + the tiny model brains
389
+ pytest # 327 tests, no display or network needed
390
  ```
391
 
392
  The accessibility detector needs system packages rather than an extra:
 
502
  | `skills.py` | **2.0** - Skills: a *verified* run written down once, replayed by `SkillBrain` with no model. Labels, never coordinates |
503
  | `gates.py` | **2.0** - Approval gates: `AllowOnlyLabels`, `InteractiveGate` (yes / no / always / never), `AllOf` / `AnyOf`. A refusal is a step |
504
  | `runner.py` | **2.0** - `TaskRunner`: a queue of goals, a JSONL resume file, and a `RunReport` that counts what was *verified* |
505
+ | `watchdog.py` | **2.0** - `Watchdog`: a deadline on `decide` / `execute` / `capture`, so a hung call is a step with a reason, not a stall |
506
+ | `audit.py` | **2.0** - `AuditLog`: an append-only, hash-chained record of a run. Edit, delete or reorder a line and `verify_audit` names it |
507
  | `showcase.py` | The capability gallery: one real screenshot per capability, checked against the public API |
508
  | `measure_vlm.py` | Measures the four ways to ask a model, on a real screen, and prints the table |
509
  | `evaluate_daily.py` | A day's tasks against a real app, verified by the app's own log |
 
554
  reads `last action: Save` afterwards, and the app wrote `Save` to its marker file.
555
  `--detector best` tries the tree first, then OCR, then the numbered grid.
556
 
557
+ **Honest limits.** AT-SPI is Linux-only here. UI Automation *is* implemented - `UiaReader` and
558
+ `UiaDetector`, unit-tested against a synthetic control tree - but it has never run against a
559
+ real Windows desktop, and `accessibility_available("uia")` reports the truth on any machine
560
+ rather than pretending, so an agent on Windows still falls back to OCR. Tk barely publishes a tree and a canvas publishes none,
561
  which is why this is a detector and not a replacement.
562
 
563
  ## Can it do a day's work?
 
611
 
612
  ## Capability gallery
613
 
614
+ **74 capabilities, one screenshot each - and 163 of the package's 270 public callables (functions, methods, classes and protocols) appear in at least one of them**, together with 8 of its 26 public constants. **Not yet pictured: 107 callables** - 103 in the 2.0 operator layer (skills 29, the batch runner 20, approval gates 19, the structural diff 14, the audit log 13, the watchdog 8) and four CLI entry points. They are covered by tests rather than by pictures, and `showcase.py` prints the exact list. The counts are read off `gallery/index.json`, which records what each picture shows, and checked against the package by `showcase.api_surface()`.
615
 
616
  Nothing here is a mock-up. Each picture is produced by [`showcase.py`](showcase.py): a command or a call is run for real, and its actual output - or the real desktop it acted on - is what you see. The desktop shots are real screen captures on a real X server (Xvfb, 1280x800), including a real mouse click verified by the target application's own reaction.
617
 
 
1239
  **Works:** real capture, a real OCR index with coordinates that land on the right pixel,
1240
  a real click an app reacts to, verified success, the closed vocabulary, the policy gates,
1241
  the no-progress guard, echo detection, the doctor, the CLI, portable traces that score a brain's choices offline, skills learned from verified runs,
1242
+ a resumable task runner, operator approval gates, a watchdog that refuses to wait forever rather than stalling silently, a hash-chained audit log, 327 tests, a 256M VLM that
1243
  reads a button label from pixels on a clean screenshot — and the same suite passing inside
1244
  a real Windows Server 2022 guest with no KVM (109 passed, exit 0, with the OCR-inference
1245
  tests excluded as impractically slow under emulation).
1246
 
1247
  **Does not work yet:** reliability on a *live* screen. The 256M VLM echoed the prompt
1248
+ there; the 0.5B text planner picks wrong actions; UI Automation has never been exercised
1249
+ against a real Windows desktop, so an agent there still reads labels from OCR; and the
1250
+ harness still trusts a model's `done` when no verifier is given.
1251
 
1252
  ## Roadmap
1253
 
 
1272
  - [x] **2.0** Operator approval gates - a label whitelist, or ask before every action
1273
  - [x] **2.0** A resumable task queue with a report, and structural verification of "it worked"
1274
  - [x] **2.0** `skills` and `batch` subcommands, and an example queue at `tasks/day.json`
1275
+ - [x] **2.0** A watchdog: a per-call and whole-episode deadline, so a call that never returns
1276
+ becomes a named step instead of a console that looks like it is thinking
1277
+ - [x] **2.0** An audit log: an append-only, hash-chained record of a run, and `--verify-audit`
1278
+ to check it - so the evidence survives the container that produced it
1279
+ - [x] **2.0** `--gate`, `--audit` and `--verify-audit` on the command line, and the shared
1280
+ AT-SPI guard, so a machine without the typelib skips rather than failing
1281
+ - [ ] A gallery run that pictures the 2.0 additions: **107 of the package's 270 public callables**
1282
+ have no screenshot yet - 103 in the operator layer and four CLI entry points. Adding the
1283
+ entries to `showcase_catalog.py` is what closes it
1284
  - [ ] **Verify UI Automation** (Windows) against a real Windows desktop. The reader and the
1285
  detector are implemented and unit-tested against a synthetic control tree, and
1286
  `accessibility_available("uia")` reports the truth on any machine - but no Windows