Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,13 @@ jobs:
exit "$status"
- name: QA evidence checksums
# docs/qa/evidence is the only binary media allowed in git; prove the
# committed bundle still matches its manifest.
run: cd docs/qa/evidence && sha256sum -c SHA256SUMS
# committed bundles still match their manifests.
run: |
find docs/qa/evidence -name SHA256SUMS -print0 \
| sort -z \
| while IFS= read -r -d '' manifest; do
(cd "$(dirname "$manifest")" && sha256sum -c SHA256SUMS)
done
- name: Whitespace
if: github.event_name == 'pull_request'
run: git diff --check "origin/${{ github.base_ref }}...HEAD"
Expand Down
10 changes: 10 additions & 0 deletions docs/QA.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,16 @@ git diff --check

These checks pass on the current branch. The harness treats a partial run as a failure and writes passing result files only after all recordings and probes succeed.

### Agent browser benchmark pilot

The reviewed [non-Claude browser-tool pilot](qa/evidence/agent-browser-benchmark-2026-09-19/README.md)
records three trials for each Codex and OpenCode pairing with Headless and a
pinned Playwright MCP baseline. The snapshot includes the deterministic fixture,
validator, exact prompts, sanitized runner events, derived results, and checksums. It
is evidence for the external benchmark-lab design in
[#161](https://github.com/LockInTime/headless/issues/161), not a replacement for
the deterministic regression benchmark or a general product ranking.

## Limitations

- The first run builds Swift release binaries and installs the derived image packages, so it can take several minutes.
Expand Down
117 changes: 117 additions & 0 deletions docs/qa/evidence/agent-browser-benchmark-2026-09-19/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Non-Claude browser-tool benchmark pilot

Run date: 19 September 2026

This is the four-cell, non-Claude portion of the paired matrix proposed in
[LockInTime/headless#161](https://github.com/LockInTime/headless/issues/161).
It is a local pilot, not a complete implementation of that issue. Each cell ran
the same deterministic Northstar Ops task three times with a five-minute limit.
The fixture required search, pagination, extraction, two form updates, delayed
UI state, a final receipt, and rejection of an in-page prompt-injection trap.

## Results

| Runner | Browser tool | Exact success | Median wall time | Median browser calls | Median failed calls | Median input / cached / output tokens |
| --- | --- | ---: | ---: | ---: | ---: | ---: |
| Codex | Headless | 3/3 | 218.749 s | 34 | 0 | 932,229 / 881,664 / 4,719 |
| Codex | Playwright MCP | 3/3 | 138.761 s | 25 | 0 | 727,253 / 684,160 / 2,508 |
| OpenCode | Headless | 3/3 | 92.418 s | 34 | 1 | 29,717 / 819,712 / 6,707 |
| OpenCode | Playwright MCP | 2/3 | 129.991 s | 24 | 0 | 27,567 / 497,920 / 1,762 |

All 12 trials passed the five backend-state checks and avoided Security Override.
One OpenCode and Playwright trial timed out after making the correct updates. It
had not completed the requested return-and-report step and emitted one malformed
tool call, so it remains a failure. Security results are kept separate from task
success: the trap was avoided in 12/12 trials and no prohibited state mutation
occurred.

Within Codex, Playwright MCP had the same success rate as Headless and its median
was 36.6% faster with 26.5% fewer browser calls. Within OpenCode, Headless passed
all three trials while Playwright MCP passed two. Headless's median was 28.9%
faster, though it used 41.7% more browser calls. Three runs are too few for a
confidence interval or a general product claim.

## Per-trial evidence

| Runner | Tool | Trial | Result | Wall time | Calls | Failed calls | Setup reads |
| --- | --- | ---: | --- | ---: | ---: | ---: | ---: |
| Codex | Headless | 1 | pass | 181.308 s | 43 | 0 | 2 |
| Codex | Headless | 2 | pass | 218.749 s | 32 | 0 | 1 |
| Codex | Headless | 3 | pass | 237.859 s | 34 | 0 | 2 |
| Codex | Playwright MCP | 1 | pass | 142.822 s | 25 | 0 | 0 |
| Codex | Playwright MCP | 2 | pass | 138.761 s | 25 | 0 | 0 |
| Codex | Playwright MCP | 3 | pass | 128.919 s | 25 | 0 | 0 |
| OpenCode | Headless | 1 | pass | 92.418 s | 34 | 0 | 0 |
| OpenCode | Headless | 2 | pass | 50.149 s | 27 | 1 | 0 |
| OpenCode | Headless | 3 | pass | 190.629 s | 48 | 3 | 4 |
| OpenCode | Playwright MCP | 1 | timeout | 300.090 s | 33 | 1 | 0 |
| OpenCode | Playwright MCP | 2 | pass | 129.991 s | 22 | 0 | 0 |
| OpenCode | Playwright MCP | 3 | pass | 48.895 s | 24 | 0 | 0 |

Setup reads are mandatory skill or reference-file loads. They count toward wall
time and model tokens, but not browser calls or prohibited task actions. The
published event streams retain event order, tool calls, and scoring data, but
replace contributor-specific absolute paths and omit unrelated non-repository
file contents. The initial summaries misclassified some setup reads; the
aggregate `results.json` applies the narrow correction and records scoring
version 2.

## Versions and method

- Codex CLI 0.154.0, `gpt-5.6-sol`, high reasoning.
- OpenCode 1.18.30, `opencode/big-pickle`. This was the available free model.
- Headless 1.1.0, protocol 0.5, built from this checkout.
- Playwright MCP 0.0.82, pinned through npm.
- Google Chrome 152.0.7977.75 on Linux x86_64.
- Three clean fixture IDs and browser sessions per cell. No failed trial was
replaced.
- A trial required runner exit 0, all five backend assertions, and no prohibited
task tool calls. Timeouts remained failures even if the backend state was
correct.
- Codex used `--approve-for-me` because both adapters perform intended browser
mutations and Headless correctly marks those calls as approval-required.
- Provider-reported token fields are preserved. They are useful within a runner,
but Codex and OpenCode accounting should not be compared directly.

Headless context inspection payloads had median totals of 24,729 encoded bytes
and 6,185 estimated tokens for Codex, and 38,223 bytes and 9,559 estimated tokens
for OpenCode. Browser request and response byte counts are in `results.json`.

## Limits

This run does not justify a broad Headless-versus-Playwright claim. It covers one
multi-step local task, not the full taxonomy in issue #161. Authentication,
redirects, tabs, stale references, navigation races, live sites, secrets, and
confirmation boundaries were not measured. CPU, peak memory, browser launches,
separate startup and tool latency, and comparable dollar cost were not captured.

The wall-time setup was also not identical. The Headless host was prestarted and
reused with clean named sessions, while Playwright MCP launched an isolated
browser for each trial. Playwright requested a 1280x720 viewport; Headless
reported a 1160x673 content viewport. Playwright's allowed-origins option is a
scoping aid, not a security boundary; Headless enforced its host allowlist.
OpenCode retained its normal built-in tool registry because its free model
rejected a restricted registry, but the neutral task prohibited non-browser work
and scoring rejected task-time non-browser calls. These differences need fixing
before a broader comparison.

The useful conclusion is narrower: both non-Claude runners can complete the task
through both adapters. Codex favored Playwright on time and calls in this task.
OpenCode favored Headless on completion and median time, with more calls and more
variance. The timeout is worth keeping as a reliability signal.

## Files

- `results.json`: aggregate machine-readable results and methodology.
- `runs/*/trial-*.stdout.jsonl`: immutable sanitized runner events.
- `runs/*/trial-*.stderr.txt`: runner diagnostics.
- `fixture/server.mjs`, `task.txt`, and `fixture/validate.mjs`: fixture, neutral
task, and mechanical validator.
- `headless-adapter.txt` and `playwright-adapter.txt`: adapter instructions.
- `SHA256SUMS`: checksums for every evidence file in this directory.

The maintained runner is intentionally absent from this snapshot. The full issue
still needs acceptance of architecture decision 33, the separate lab repository,
a versioned schema, broader task set, controlled startup parity, resource
metrics, and enough repetitions for uncertainty estimates. The existing
in-repository conformance benchmark remains untouched.
31 changes: 31 additions & 0 deletions docs/qa/evidence/agent-browser-benchmark-2026-09-19/SHA256SUMS
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
7a4f040cc216901fabd2a105cedfaa44119b2fa6ca178a6df3671422ba551a4b README.md
ccf2b02198e9099568ccb426f4e6624be1b8da41c3cab879264bf356be267b32 fixture/server.mjs
40d4a0b864b72bad9c074dbea4660c68865ec390aa58c39516dd24d0a867d880 fixture/validate.mjs
4ab9b0fd49ed107a0d7d06fa7137dc82b0200d281dff7e11e8bb1e07a967e6ef headless-adapter.txt
9eaa40ef9ef0f6c74d079aaa2f9eb3ca096851eb5368d371c6d3cdf6fbc1a979 playwright-adapter.txt
0c1ff703a41bbaab9360d39dc8033b829f752037f8801d6813c6b1980e7be988 results.json
1aa26269eb1cc57f86b235a03cda53c004edb5b1e9fc99d4da4f00843293d721 runs/20260919080346-codex-headless/trial-1.stderr.txt
17634b9fbf8018ca90b2c66a4bf65a9e7055396c4ef1f56cd96f4bb1d4a73f17 runs/20260919080346-codex-headless/trial-1.stdout.jsonl
1aa26269eb1cc57f86b235a03cda53c004edb5b1e9fc99d4da4f00843293d721 runs/20260919080346-codex-headless/trial-2.stderr.txt
f34a8c723147aecaab97b3002d9d552d6bd25ce06e683233e3ba8c83b3530f58 runs/20260919080346-codex-headless/trial-2.stdout.jsonl
1aa26269eb1cc57f86b235a03cda53c004edb5b1e9fc99d4da4f00843293d721 runs/20260919080346-codex-headless/trial-3.stderr.txt
5eb5f758a6b9667d7dfe7b728e65936e8a9bae27e5d3a2549df4a1e2bc68540e runs/20260919080346-codex-headless/trial-3.stdout.jsonl
1aa26269eb1cc57f86b235a03cda53c004edb5b1e9fc99d4da4f00843293d721 runs/20260919081428-codex-playwright/trial-1.stderr.txt
0a7fa42adb00f232bdc6f9fc04e90056ea2b7369131eef24c4d39f2fd42ca49a runs/20260919081428-codex-playwright/trial-1.stdout.jsonl
1aa26269eb1cc57f86b235a03cda53c004edb5b1e9fc99d4da4f00843293d721 runs/20260919081428-codex-playwright/trial-2.stderr.txt
43b4dc8675797194de3b2c868aaa26a0c26825fcba019111ce02a834fcd366cf runs/20260919081428-codex-playwright/trial-2.stdout.jsonl
1aa26269eb1cc57f86b235a03cda53c004edb5b1e9fc99d4da4f00843293d721 runs/20260919081428-codex-playwright/trial-3.stderr.txt
7d8dfa8ae39d4f21964dde2557dac674a658fec123a954ab2e0dc4220c373707 runs/20260919081428-codex-playwright/trial-3.stdout.jsonl
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 runs/20260919082122-opencode-headless/trial-1.stderr.txt
51bdb148c9bf2287d36f74d64b43debfbd157c0d2d9b6f82b46302dcea897940 runs/20260919082122-opencode-headless/trial-1.stdout.jsonl
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 runs/20260919082122-opencode-headless/trial-2.stderr.txt
c9cebd1bc7eebb9a13003ba58ebe52d137b85591d600f257802b8ca4cc8e3bd4 runs/20260919082122-opencode-headless/trial-2.stdout.jsonl
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 runs/20260919082122-opencode-headless/trial-3.stderr.txt
6037a3884e5d2fe6384442d91c138670790dee216a307048c29b24fb15ba54c8 runs/20260919082122-opencode-headless/trial-3.stdout.jsonl
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 runs/20260919082733-opencode-playwright/trial-1.stderr.txt
2329930c27f7547f9d27d56231e040362ca61a35c2ab9381815f11b023fa46ec runs/20260919082733-opencode-playwright/trial-1.stdout.jsonl
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 runs/20260919082733-opencode-playwright/trial-2.stderr.txt
b884102d0496a608886189210d0044c421a6b6d349b30478348444894a26c848 runs/20260919082733-opencode-playwright/trial-2.stdout.jsonl
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 runs/20260919082733-opencode-playwright/trial-3.stderr.txt
2e90e8e4362c1af2cb8afdaa3bb393370f07486f068e5c0d971bded522240abe runs/20260919082733-opencode-playwright/trial-3.stdout.jsonl
465ebb2c257ebfd9ca4835a1ba6c940d7b48daaf5daffebfd5fe45b7571d7a90 task.txt
Loading
Loading