Repository navigation
From a nine-lens adversarial audit. Assertions that reported success without checking now tell the
truth, so a green test suite can go red. See MIGRATION.md for every behaviour change.
Fixed: assertions and tools that lied
assert_accessibleandassert_no_a11y_violationsread a key the audit never produced and could not
fail. A failed lookup could read as a met condition in locator matchers; negative matchers passed on a
missing element;no_ghost_commandsfailed on the wrong list;has_textsearched snapshot JSON;
ipc_was_not_calledpassed on a log window that could not see the call.wait_for expectedandassert_semanticdisagreed on equality; both now share one rule, which no
longer callsnulland"null"equal.explainandintrospect coverageturned an unreadable page into a clean "nothing happened".recording events_betweenhid events the ring buffer had evicted, andcheckpointmissed what the page
captured just before it.windowignored its target and acted on the default window.resizeandmove_toreported the request,
not the outcome.query_dbsilently changed big numbers,1.10and duplicate keys in JSON text, and returned infinities
as NULL.select_option,fillandtype_textreported success for values that never applied.
Fixed: crashes and hangs in the host app
- Deeply nested SQL or a crafted database schema could overflow the stack and kill the app. Both now return
a clean error (64 MiB reserved stack, nesting and view-chain budgets, which read SQL the way SQLite tokenizes it
and each schema entry the way SQLite loads it, so a UTF-16 BLOB counts). A check that runs out of time refuses. - Windows process-memory reads leaked a handle per call. The event bus could retain hundreds of MiB.
- Logging: reading the log no longer stalls logging threads; a panic in a
Debugimpl, a value that logs
while being recorded and two capture layers in one subscriber no longer panic or deadlock; symbolising a
panic no longer blocks workers or another panic;log_layer()no longer lowers the global max level. navigate go_toout of the app left a dead page with no way back; a page stopped bywhile(true)now
recovers through a detour on WebView2, and on Linux by ending the one web process whose main thread spun throughout,
only if every other window that has answered still answers with that process paused; the result names it
(ended_web_process). From a stopped page inside the app,recoveredandokfor a page inside the app mean a new
page answers there, where they used to mean a navigation was sent: WebKit's URL reads the new address while the old
script still runs. The demo's sync window-building command deadlocked.- A route regex that can hang the page is refused at
add, by what a repeated group can match. Polynomial
patterns still get through: no repeated group (.*.*.*.*x), or a chain of them ((a)*(a)*(a)*(a)*y).
Fixed: JS bridge
- Refs carry a per-page-load tag, so a ref from another page or window can never resolve to the wrong element.
- A page could pollute prototypes or hook built-ins to forge or hide bridge results and logs, and could add
route rules: closed. Bridge comments that overclaimed are corrected. Results and logs are evidence against
a buggy page, not a hostile one (docs/src/security.md). find_elementscomputes accessible names and honestvisible/enabled, returns deepest text matches, and
gainsattribute,attribute_value,text_exactandinclude_hidden.- Actionability: SVG,
opacity:0styled controls, MUI wrappers, labels, disabled fieldsets, shadow DOM events,
contenteditable and same-origin iframes. Whether a click reaches an element is now the browser's answer at real
points of it (centre, SVG outline, line boxes, a grid, descendants), not geometry: closed accordions,.sr-onlyand
::afteroverlays are covered, and a control with a hole, a stroke-only circle and a link with no box of its own
are clickable. A trusted click uses the point found, on a whole device pixel, and is refused where its point cannot
be worked out: inside a scaled, rotated or zoomed frame, or on a pinch-zoomed page. Checked in real Edge and on WebKitGTK. routefulfillworks on XMLHttpRequest, compared event for event with a real server in 21 scenarios. It used
to send the request and say so.animation scrubno longer fires the page's own animation and transition events for its seeks: a toast
removing itself onanimationendsurvives a scrub.- A bridge call or log read on a page with no bridge is a tool error; it used to answer
undefinedor an empty list
as a success. type_textno longer corrupts number and date inputs. Log entries are bounded. Scrubbing restores the
animation's time and state.
Fixed: privacy
- Invalid custom redaction patterns fail
build(). Redaction covers numbers, name/value pairs,storage getand
short credential names.wait_for eventomits the payload where the event bus is not allowed. Legacy
disabled_toolsnames block their actions. The Test profile's allowlist promise now works. Refused requests
cannot flood or write into the log.
Fixed: CLI and watchdog
victauri run: output reaches the terminal as it arrives, killing the launcher takes the app with it, on Unix
even by SIGKILL (a small helper), and a closed stderr no longer changes the exit code. Old captures are pruned.
A launcher killed outright is now said, bylogs stdout(launcher_gone) andvictauri logs.- A stale discovery entry whose PID was reused, naming the current app's port, no longer makes
--apprefuse with
"several apps": the server says which entry is real (/infonow reportspid). In the CLI, bridge, test client
and VS Code extension. A server refusing every token settles nothing, and asking is bounded to about 2 s a scan. logs stdoutcursors hold the file's tag, so a rotation landing on a record boundary is seen and two rotations
are reported as a gap. A reader racing a rotation could lose thousands of lines silently (19,413 to 32,808 of
150,000 in a stress test): a file's tag and bytes now come from one open, here and invictauri logs --follow.victauri testfirst-launch default is 20 s: a cold webview measured 12.5 s against the old 10 s budget.- Bridge: a
VICTAURI_PORTpin that is down never reaches another app. Invalid UTF-8 no longer shuts it down. victauri logs --followloses nothing across rotation.setupno longer pins user-level configs to one project
and reports failures in its exit code. Output from a hostile plugin cannot drive the terminal.- Watchdog: quoted recovery paths with spaces work, and a slow recovery command is no longer killed.
- With nothing discovered, the CLI, bridge, test client and the VS Code extension's auto-connect no longer send
requests to whatever holds port 7373. The watchdog still polls it by default, and an explicit VS Code connect tries it.
Fixed: other
- Screenshots of decorated windows keep their edges (Windows.Graphics.Capture crop). Trusted clicks respect page zoom.
- Database discovery skips non-SQLite files and finds
.db3. The view-chain budget reads only places that name a
table, so a column named like a view no longer refuses a healthy database. /mcpnames the problem whenargumentsis not an object, where it said the method does not exist.
find_elementsin the test client takes a string as CSS.screenshotnames the window it captured.- The docs name the filter that keeps rmcp's per-request INFO lines off an app's console (
info,rmcp=warn). With a
plaininfofilter they still appear. - A bare
e0ref means that counter on the current page: a real consumer's suite hardcoded one. Performance metrics
survive a reload's moment with no body.
Changed: release and CI
rusqliterange extended to<0.42; lockfile updates move CI onto rmcp 3.8, tauri 2.12, wry 0.57, tao 0.37 and
tokio 1.54.1, which consumers without a lockfile already resolve.- Release workflows use no caches (new guard
scripts/check-release-no-cache.sh). The crate-exists check no longer
misreads a published crate.release-vscode.ymlrequires green CI, including the Windows job.
mcp-registry.ymlrefuses an unpublished version.surface-audit.ymlcovers the registry and GitHub Release. - A new CI leg runs the demo with auth on, and a new test opens a second window.
See MIGRATION.md for upgrade steps. Binaries: verify with sha256sum -c SHA256SUMS.
Commits
- fix: 0.10.3 follow-up before publishing - never end the process of a window that answers (#99) (fa293b6)
- release: v0.10.3 - assertions that tell the truth, from a nine-lens audit (#98) (d3cbfd9)
- release(vscode): extension 0.10.3 - ship the owner-check retry fix (#97) (920884f)
- fix(vscode): extension 0.10.2 — Windows owner check fixes, CI on Windows (#96) (1001d11)
- docs(CLAUDE.md): v0.10.2 published (#95) (6242da9)