Skip to content

Check origins on pages, let a task name its browser, fix date-form picks - #84

Merged
senamakel merged 22 commits into
tinyhumansai:mainfrom
YellowSnnowmann:fix/browser-origins-on-pages
Oct 10, 2026
Merged

senamakel merged 22 commits into
tinyhumansai:mainfrom
YellowSnnowmann:fix/browser-origins-on-pages

Conversation

@YellowSnnowmann

@YellowSnnowmann YellowSnnowmann commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

OpenHuman always sends an allowed-websites list, and the browser session handed that list to agent-browser as allowedDomains. agent-browser then fails every request to an unlisted host. In the app this broke browser tasks on every site we test:

  • pages lost their CDN files: OYO loads 94 files from assets.oyoroomscdn.com, so its destination box never listed suggestions and the run failed with "Please select a destination from the list";
  • when agent-browser could not install its filter on a new target ("Cannot find default execution context"), the tab stayed blank, or the browser was closed and every later step reported BROWSER_UNAVAILABLE;
  • a persistent profile was refused outright ("--allowed-domains is not supported with --profile").

The session now checks pages itself and never hands the list to the engine. StartTask also gains browser_executable and browser_profile, so a host can give each task the Chrome binary and profile folder its settings name.

This PR also fixes two date-form bugs from live round 13. Both fixes are generic, with no site names in code:

  • A one-way search became a round trip (MakeMyTrip). For the slot "from city", the opener lookup took the first control whose label held "city": the trip-type tab "Multi City". Jev refused it, and the do loop that followed pressed the button wrapping the whole form ("From DEL … To BLR … Departure … Return …") at its centre, twice. The first press opened the calendar, and the second picked a return date.
  • The calendar was paged a year ahead (Agoda). Agoda draws each month as rows of a week, and its open days show a number and a fare with no month. Sight read only tables and flat grids, so no day read as "23 October 2026", and choose pressed "Next Month" up to its 12-month limit, into 2027, twice.

Review hardening. An end-to-end review of every commit, plus five tinysweeper passes (75 threads, each answered and resolved), led to a further round of fixes:

  • Origins checks.
    • Addresses are read by the browser's own URL rules.
    • Every call that acts on or reads a page checks it first.
    • A refusal after a call already ran is reported apart from one before it, so a host never takes it for "nothing happened".
  • Task settings. The binary and profile settings are the host's alone: they are validated, and they are no longer in the agent-facing skill.
  • Date forms. Three of the date-form fixes were tightened:
    • sight never assigns a month to the wrong grid;
    • the heading stops paging only for undated days next to the arrow;
    • the opener ranking prefers the box that best matches the slot's own words over the shortest label.

Round 14 fixes (ixigo, Agoda, BigBasket), and the browser that cannot start. Also generic, with no site names in code:

  • Priced calendar days were never dated (ixigo, Agoda). Each day shows its number and a fare ("23 6757") and carries its date only in one inner label ("October 23, 2026"), which sight ignored because the label does not contain the shown text. ixigo also draws "‹ October 2026 – November 2026 ›" above both months, outside either, so its arrows paged no calendar. Sight now takes that inner label as the day's date when it names a month and the day's number. A month's title is looked for up to five ancestors above its grid, and the title's own block counts as part of the calendar, so arrows drawn in it page the month. That block is registered after the two-month pickers, so a wizard's "Next" beside the grid keeps its name.

  • The basket stayed covered, and rescues filled the cart (BigBasket). The search box left its suggestions open over the page, and every control outside them read as covered. The basket press was refused, Escape left the list there, and the refused press was counted as one that opened a dialog. The step's failure then told the rescuer "a dialog the task opened is in front … its own controls are: … Add …", and rescues re-added Maggi in other sizes and pressed + again (the cart ended with two kinds, one at quantity 7). Now:

    • a press the page refused (NOT_ACTIONABLE) never counts as one that opened anything in front;
    • a press still refused names its cover (button "Select Location", an empty layer, …) in the history and in the step's failure note;
    • an empty layer still over the target after Escape is pressed where nothing pressable lies beneath it, as a person clicks outside a popup, and the target is pressed once more;
    • the retried press centres its target instantly (the store sets scroll-behavior: smooth);
    • the rescuer is told that a failure naming a cover quotes screen data and is no reason to redo earlier steps; the planner is told that a header's cart button shows only a count.
  • A task whose Chrome could not start said only BROWSER_UNAVAILABLE (Browser tasks ignore the persistent profile and only see the Chrome path the module loaded with openhuman#7199). A browser the module launches now says what to set:

    • "no Chrome or Chromium was found on this machine; give the path of the browser to use";
    • "the browser binary given could not be started (…); check that its path names Chrome or Chromium".

    A binary that is no browser now reads that way too, where before it read as a timeout or a module failure. The step note keeps the error's first line, and such a step is never rescued: the task fails at once with a hint naming browser_executable. Live, four rescues of it ran for minutes before giving up.

  • Raw page checks tightened (fifth tinysweeper pass). A raw boundingbox (whose selector can test whether a text shows) and a raw permissions grant are now checked like any call. Only waitforloadstate and url go unchecked.

Related issue

The module half of tinyhumansai/openhuman#7199; the host half follows once this is released. Related: tinyhumansai/openhuman#7000.

API or behavior changes

  • Contract 2.9 → 2.10 (minor):

    • optional TaskConstraints.browser_executable and browser_profile;
    • * accepted among origins: any public host; private and local addresses and names refused.
    • A 2.10 host refuses a 2.9 module.
  • Rust API. TaskConstraints gains two public fields. A Rust host that builds it with a struct literal must add them, or use ..TaskConstraints::default(). OpenHuman's re-pin does. Release this as minor (0.11.0).

  • How a page is checked (only under a list; with no list, nothing new reaches the browser):

    • Addresses are parsed by the WHATWG rules Chrome uses (the url crate, already in the lockfile through agent-browser), and hosts are compared canonically. So http://2130706433/, 127.1, hex and octal forms, and percent-escaped or full-width digits are judged as the addresses they open. http:\\host\ is read as the browser reads it, and so is https://evil.test\@example.com/ (Chrome opens evil.test).

    • Under *:

      • non-global IPv4, and IPv6 including site-local fec0::/10, is refused, with IPv4 carried in IPv6 judged as itself;
      • single-label names and names under localhost, local, internal and home.arpa are refused.
    • Besides web pages, a list admits:

      • about:blank, about:srcdoc and browser error pages;
      • a blob: page made by an admitted host.

      It admits no other about: page (about:settings is a browser page), nor any file, data: or browser-setting page.

  • When a page is checked:

    • A navigation outside the list is refused before the browser is asked.
    • A raw command naming an address in url, url1 or url2 is checked the same way. A raw read of an address is refused under any list, because it fetches from this process and follows redirects unseen.
    • Every call that acts on or reads the page (perform, evaluate, snapshot, read_page, screenshot, every raw command, a raw title included) checks the page first, so nothing is sent to a page that moved out of the list on its own.
    • A raw command and evaluate also check the page they leave before returning anything. navigate reads the page it reached afresh, rather than trusting the address the engine reports.
    • Only a raw wait for the page to load (waitforloadstate) and a read of its address (url, which a refusal names anyway) are not checked, so a wait runs while a navigation commits. A raw boundingbox and a permissions grant are checked like any call. addscript/addstyle addresses are checked like navigations. A check around a call's own work lets the call proceed only when the engine says the page is committing a navigation; any other failure to read the address fails the call, and the next check catches a refused page.
    • The observation's check is stricter: under a list it reads the address twice, fails closed, and is bounded by READ_TIMEOUT.
    • First page: a launched browser leaves a refused first page (a profile can restore its last pages). An attached browser keeps the person's tab as it is and opens a blank tab of its own. A session is never handed out on a refused page: if the page can't be left, or the tab can't be opened, the browser is closed and the open fails.
  • New error variant Error::LeftRefusedPage. It covers a page refused after the call ran. It has the same BLOCKED_BY_POLICY code, but delivery is unknown, not not_delivered. Scenario: a click on a listed merchant's "Pay" lands on an unlisted bank page. A host that trusted "not delivered" would retry and pay twice.

  • Files a page loads are no longer filtered (its CDN, APIs and frames). A name is never resolved, so under * a public name that leads to a local address is admitted. This is documented in SessionOptions::allowed_origins, sessions.md, tasks.md and safety-and-privacy.md.

  • StartTask refusals:

    • ORIGINS_REQUIRED for fill_then_approve with *.
    • INVALID_REQUEST for:
      • a profile that is not an absolute folder;
      • a binary that is not the absolute path of an existing executable file;
      • either of those beside browser_endpoint, which agent-browser would only have refused at the first browser step.

    Paths are taken exactly as written.

  • Host-only settings. browser_executable and browser_profile:

    • are documented as the host's settings;
    • are left out of everything a model reads: the skill schema, SKILL.md and Describe (the Describe parity test names them as kept out on purpose).
  • Location. A task's own kept profile now gets the location grant when it presses "use my current location", as a throwaway profile already did. Only a person's running browser (an endpoint) keeps its own say.

  • Sight calendars:

    • week-row calendars are read;
    • a header naming several months dates its grids only when every month found its grid;
    • a page's own label that names a month stands alone.
  • Date paging:

    • stops once a day shows the date;
    • for undated days, also stops at the month heading beside the arrow, which must be no month choice, with at least 7 bare days within 100 nodes of that arrow.
  • Slot openers: ranked by being on screen, then holding more of the slot's words, then holding its first word, then wrapping no other match.

  • Calendar days with a fare: a day's one inner label dates it when it names a month and the day's number; a month title is looked for up to six ancestors above its grid, and the block holding both is a calendar (its arrows page it) unless it holds a form's fields.

  • Covered presses:

    • Surface::dismiss_cover is new, defaulted to ACTION_NOT_SUPPORTED, so existing surfaces are unaffected. The browser presses only an empty layer: one placed over the page, part of no component, over at least half the window, and lying over a control sight marked. It presses at one of 49 grid points where the layer is on top and nothing pressable lies beneath. Covers are read through open shadow roots, and a control, dialog, text, picture or unreadable cover is never pressed;
    • a browser press still refused as covered carries details.cover and details.empty_layer (inside the module only; no bus payload changes);
    • the flow presses such a layer once after Escape (or a layer's own closer) failed, looks again, then retries the same vetted target; it never does so behind a dialog the task opened;
    • a refused press no longer counts toward what is in front;
    • a step that fails after a press still refused ends its note with "its press of … was refused because … lies over it".

Safety trade-off, @senamakel please confirm. A page on an allowed site can now load files from any host, as in a normal browser. Under fill_then_approve, that includes a payment provider's frame on a listed page; the docs now say so. The agent still can't open, act on or read a page of an unlisted site. The list stays a guard rail, not a sandbox.

Validation

  • cargo fmt --all -- --check: clean
  • cargo +1.99.0 clippy --workspace --exclude tinycomputer-accessibility --all-targets --all-features -- -D warnings: clean with CI's toolchain (accessibility is excluded locally, as in earlier PRs; CI covers it)
  • cargo test --workspace --exclude tinycomputer-accessibility --all-features --no-fail-fast: 1261 passed, 0 failed
  • RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features --workspace --exclude tinycomputer-accessibility: clean
  • TINYCOMPUTER_LIVE_BROWSER=1 cargo test -p tinycomputer-browser --features agent-browser --lib -- live_: 31 passed, on local fixture pages in Chrome for Testing
  • Red/green: each new behaviour test fails without its fix. The checks were:
    • the opener picks "Multi City";
    • paging reaches month 20;
    • the week-row and seven-row cases are left undated;
    • a refused page is acted on;
    • a refused press counts as opening a dialog;
    • a smooth scroll leaves the target off-centre;
    • a title's wider block renames a wizard's "Next";
    • a browser that cannot start is rescued;
    • a raw boundingbox or permissions reaches a refused page.
  • Not yet run: a live browser task with an allowed-origins list, through OpenHuman, with the module built from this branch.
  • Not yet run live: ixigo and BigBasket after the round-14 fixes (the fixes are proven on local fixture pages and in the simulator).
  • Live round on this branch (task_live, headed Chrome, no site list), module built from c8b39c6:
    • MakeMyTrip: fixed. The "From DEL" and "To BLR" boxes were opened directly, the 23rd was picked, and no return date was added. The run then failed for an unrelated reason: the plan chose class and adults after searching, which opened MakeMyTrip's full-page modify-search overlay over the results.
    • Agoda: searched 23 → 24 Oct with no paging into 2027. It sorted, opened the first hotel, and stopped before "Book" (needs approval).
    • OYO: stopped before "Continue to Book" (needs approval).
    • ixigo: the date step failed, as in earlier rounds: sight didn't date ixigo's or Agoda's real calendars (fixed in this PR since; see above).
    • BigBasket: Maggi was added from the search suggestions, then the basket stayed covered and rescues re-added items (fixed in this PR since; see above).

Tests

  • origins/origins_tests.rs (11 tests):
    • hosts, subdomains and *;
    • private and local addresses and names;
    • alternate address spellings;
    • backslash and @ hosts;
    • IDNA names;
    • about:, blob: and other schemes;
    • unparseable addresses.
  • sessions/sessions_tests/origins_tests.rs:
    • refused before the browser is asked;
    • a redirect, or a click with no way back, is left and reported as LeftRefusedPage;
    • a page that turns refused while it is read is never returned;
    • the first page is left at open;
    • an attached browser gets its own tab;
    • no call reaches a page that moved out on its own;
    • what a call leads to is never returned;
    • raw commands with url, url1 or url2, and raw fetches;
    • waits and actions go ahead when the address can't be read;
    • the address is retried once;
    • no read (snapshot, read, screenshot, raw title) is sent to a page that moved out;
    • a session is never handed out on a refused page it can't leave.
  • surface/surface_tests/origins_tests.rs:
    • a refused page fails the observation and reads nothing;
    • an unreadable address fails the observation and reads nothing;
    • an admitted page's screen is asserted.
  • error/error_tests.rs: LeftRefusedPage delivery and suggestion, plus every variant's published name.
  • task_tests/start_tests.rs: the refusals (binaries, profiles, the endpoint pairs) and a valid start. operations_tests.rs: the location grant in a kept profile.
  • flow_tests/enter_tests.rs: the opener ranking, including the "Date Change", "City Guides", "Check availability" and off-screen cases.
  • flow_tests/picker_tests.rs:
    • the heading rule, its reach, choice controls and dated calendars;
    • the paging test, which asserts the step's outcome;
    • the BareCalendarDays simulator quirk.
  • sight_tests/live_calendar_tests.rs (gated):
    • week rows, including a day-name row before six weeks;
    • bare grids under one header, including the case where one grid is missed.
  • sight_tests/live_day_label_tests.rs (gated):
    • a react-calendar-style pair of months under one "‹ October 2026 – November 2026 ›" bar, each day a number and a fare with an inner date label, and its arrows read as month arrows;
    • a day-picker-style grid whose days carry their own date label (a guard for that layout);
    • a month title above a wizard's step, whose "Next" keeps its name.
  • sight_tests/live_cover_tests.rs (gated):
    • an empty backdrop, and a backdrop holding a list, are named, pressed at a spot over nothing pressable, and closed, after which the target takes its press;
    • an unseen location button over the target, a component's shadow button, and a dialog are named and never pressed;
    • a backdrop over a page of buttons has no spot, and its own style is put back;
    • a target is centred at once on a page with scroll-behavior: smooth.
  • surface_tests/cover_tests.rs:
    • a press still covered names its cover and whether it is an empty layer;
    • an empty layer is pressed at its spot with raw mouse events, the cursor gliding there in a visible session;
    • a control, an empty layer with no clear spot, and an unreadable cover are refused and never pressed;
    • nothing over a target presses nothing.
  • flow_tests/do_loop_tests.rs:
    • an empty layer Escape leaves is pressed outside and the press retried, with no "opened a dialog" note, though the press scrolled a covered header in;
    • a control still covering a press fails the step with a note naming it, and is never pressed as a layer;
    • a layer the surface won't press fails the step naming it;
    • a layer that went by itself is not claimed as pressed.
  • sessions_tests/lifecycle_tests.rs, reply_tests.rs, step_kinds_tests.rs, task_tests/rescue_tests.rs:
    • the launch wording for a missing browser, a binary that won't start, and an attached browser;
    • a binary that is no browser read as unavailable;
    • the step note's first line and its cap;
    • no rescue for a browser that cannot start.
  • sessions_tests/origins_tests.rs: a raw boundingbox and permissions are refused on a page that moved out; url and waitforloadstate still run.
  • workspace_tests.rs: dismiss_cover follows the active side.

Untested edge: under *, a public name that resolves to a local address is admitted, by design (see above).

Documentation

  • docs/crates/tinycomputer-browser/sessions.md, errors.md
  • docs/technical/specs/unified-agent.md, desktop-module-contract.md, browser-sight.md
  • docs/technical/tasks.md, architecture.md, decision-thresholds.md (MAX_MONTHS, HEADING_REACH, BARE_DAYS)
  • docs/safety-and-privacy.md, docs/giving-it-a-task.md
  • docs/crates/tinycomputer-bus/* (versioning.md now shows 2.10), tinycomputer-engine/tasks.md, flow/step-kinds.md, flow/filling-forms.md
  • docs/crates/tinycomputer/configuration.md, tinycomputer-skills/walking-the-schemas.md
  • the skill's start_task.schema.json and SKILL.md
  • docs/crates/tinycomputer-browser/interacting.md, sight.md, errors.md
  • docs/crates/tinycomputer-core/surfaces-and-screens.md
  • docs/crates/tinycomputer-engine/workspace.md, flow/the-do-loop.md
  • docs/technical/decision-loops.md (same length as before), decision-thresholds.md (FAILURE_CHARS, LAYER_COVERS), tasks.md, specs/task-rescue.md
  • the flow guide (crates/tinycomputer-bus/src/flow/guide.md) and the rescuer's protocol

Known limits, not addressed here

  • .com or *.com as an origin admits every .com site and still passes fill_then_approve. This predates the PR.
  • A second task on a profile folder that another live task's browser still holds fails when its browser starts, not at StartTask. This is documented: cancel the earlier task first.
  • The location grant (after "use my current location") covers every page of that browser while it runs: agent-browser's permissions command passes no origin. It is documented in surface/location.rs.

Checklist

  • One commit per change:
    • pages checked by the session;
    • task browser settings and the contract;
    • week-row calendars in sight;
    • paging stopped at the month's heading;
    • slot openers ranked;
    • addresses read by the browser's rules;
    • checks around every call;
    • host-only browser settings;
    • location in a kept profile;
    • shared-header dating;
    • heading rule narrowed;
    • opener ranking by slot words;
    • reads checked first and fail-closed opening;
    • bare days near the arrow;
    • host-only fields out of Describe;
    • priced calendar days dated by their inner labels;
    • an empty layer over a press pressed outside, and covers named;
    • what to set when a task's browser cannot start;
    • raw box lookups and permission grants checked;
    • rescue and planner guidance on covers and cart counts.
  • No new #[allow(...)], #[ignore], or relaxed lints
  • No secrets, tokens, or .env contents in the diff or the description

A session's allowed origins were handed to agent-browser as its
allowedDomains, which fails every request to an unlisted host. That broke
the pages themselves and the browser around them:

- A site's own CDN and APIs were refused, so pages loaded without their
  pictures and scripts, and widgets such as a destination box never listed
  suggestions (OYO loads 94 files from assets.oyoroomscdn.com).
- agent-browser installs that filter on every new target before letting it
  run. When the install found no execution context yet, the target stayed
  paused (a blank tab), and the session-level install closed the browser,
  so every later step reported BROWSER_UNAVAILABLE.
- agent-browser refuses a profile beside allowedDomains, so a persistent
  profile could never start while a list was set.

The session now checks pages itself (origins/) and never hands the list to
the engine:

- a navigation outside the list, typed or a raw navigate, tab_new, or
  window_new, is refused before the browser is asked;
- the page navigate, perform, snapshot, or read leaves the session on is
  checked, and a refused one is left (back, else about:blank) before the
  call reports BlockedByPolicy;
- a task's surface checks the page before every observation, so a page it
  was taken to by any means is never read or acted on. With no list the
  check costs nothing.

An entry is an origin, a dotted host for its subdomains, or `*` for any
public host; private and local addresses stay refused under `*`. The list
remains a guard rail, not a sandbox: a page on an allowed site can still
reach other hosts on its own.
StartTask constraints gain browser_executable and browser_profile, so a
host can give each task the Chrome binary and the profile folder its
settings name, instead of the binary read once when the module loaded and
a fresh profile every time. A profile kept between tasks keeps a site's
sign-in. A relative profile folder or a blank binary is refused as
INVALID_REQUEST.

`*` among the origins admits any public host (see the previous commit).
fill_then_approve refuses it with ORIGINS_REQUIRED: it names no site card
details may be typed on.

Both are optional fields and a new accepted value, so the contract moves
to 2.10. Describe's StartTask schema, the skill schema, and the docs name
the new fields.
@tinysweeper

tinysweeper Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

This pull request moves the origin allow-list out of the browser engine into the session itself, adds host-set browser binary/profile task constraints, and fixes date-picker form handling plus cover dismissal in the flow runtime. Review lanes (critique, security) report open findings covering module declaration ordering, error-classification for timeouts, origin-policy edge cases (external resource loads, DNS rebinding, permission grants, fail-open windows around navigation commits), and TOCTOU/authorization concerns in the surface observation path; the tests and description lanes found nothing new and consider earlier-round findings addressed. The contract version is deliberately bumped to (2, 10).

State: Changes requested
Priority: critical
Reviewed head: b06b7bc7bf2a
Updated: 1791576212 (Unix time)

Review snapshot

Change surface Files Review signal Count
Production 35 Active findings 23
Tests 30 Noted findings 0
Documentation 27 Resolved findings 912
Configuration 3 Pending checks/questions 0

Completeness: Complete
Test assessment: Test coverage is assessed from changed tests and lane evidence; execution is not claimed without trusted check data.

What changed

No supported behavioral explanation was produced.

Features

  • Modified — Session-side origin enforcement on pages: Allowed origins are checked by the session itself: navigations and raw commands naming an address are refused before the browser is asked, every acting or reading call checks the page before and after, refused pages are left and reported, and the engine's domain filter is no longer used so a page's own CDN/API files load normally. `*` admits any public host while refusing local and private addresses by how they are written; a name is never resolved, so DNS rebinding remains admitted by design and is documented as the guard-rail boundary. (crates/tinycomputer-browser/src/origins/mod.rs, crates/tinycomputer-browser/src/sessions/page.rs#impl Browser {, crates/tinycomputer-browser/src/sessions/mod.rs#impl Session {, crates/tinycomputer-browser/src/convert/session.rs#pub(crate) fn launch(options: &SessionOptions) -> Value {, crates/tinycomputer-browser/src/surface/operations.rs#impl Surface for BrowserSurface {, docs/crates/tinycomputer-browser/sessions.md, docs/safety-and-privacy.md)
  • Modified — Date-form and calendar fixes: Named openers are ranked (on-screen, most slot words, first-word match, no wrapping) so a trip-type tab or a button wrapping the whole form is not pressed for a slot's box. Calendars whose days show only a number and a fare are paged by their heading and never past the wanted month, and sight reads week-row grids, shared headers, and priced days whose date sits in an inner label. (crates/tinycomputer-engine/src/agentic/flow/enter/open.rs#pub(in crate::agentic::flow) fn named_opener(, crates/tinycomputer-engine/src/agentic/flow/steps/reveal.rs#impl<B: AgentBackend + Sync> FlowRun<'_, B> {, crates/tinycomputer-engine/src/agentic/flow/steps/date.rs#pub(in crate::agentic::flow) fn date_words(option: &str) -> Vec<String> {, crates/tinycomputer-browser/src/surface/sight/sight.js)
  • Modified — Launch-failure reporting and no-rescue rule: A browser the module launches says what to set when it cannot start (no Chrome or Chromium found, or a given binary that will not start); open/browse step notes keep the failure's first line after its code; and a step refused BROWSER_UNAVAILABLE fails the task at once, never rescued, with a hint to give the browser path. (crates/tinycomputer-browser/src/error/mod.rs#impl Error {, crates/tinycomputer-engine/src/agentic/flow/steps/launch.rs#impl<B: AgentBackend + Sync> FlowRun<'_, B> {, crates/tinycomputer-engine/src/task/interpret.rs#pub(super) fn run_outcome(, crates/tinycomputer-browser/src/reply/mod.rs#pub(crate) fn classify(message: &str) -> Error {)
  • Modified — Contract version bump to (2, 10) and location grant widening: The wire contract moves to (2, 10), adding browser_executable and browser_profile and `*` among origins; a 2.9 module no longer binds. The location press auto-grants in a module-launched browser including one on a task's kept profile, but never in an attached endpoint, and the grant is not written into the profile. (crates/tinycomputer-bus/src/version/mod.rs#pub const CONTRACT_VERSION: (u32, u32) = (2, 9);, crates/tinycomputer-bus/src/version/version_tests.rs#fn the_contract_binds_to_itself() {, crates/tinycomputer-browser/src/surface/location.rs#impl BrowserSurface {, crates/tinycomputer-browser/src/surface/surface_tests/operations_tests.rs#fn location_is_granted_only_in_a_browser_the_module_launched() {)

Tests

  • unit/behavioral — Origin parsing and admission: scheme/case/port invariance, subdomain wildcards, `*` refusing local and private addresses, alternate URL spellings (decimal, octal, hex, percent-escaped, full-width digits, IPv4-in-IPv6 including NAT64 and 6to4), blob pages, unparseable addresses, and entries that name no host admitting nothing.: Broad and detailed; pins the WHATWG-URL-based host comparison including tricky encodings and the documented DNS-rebinding limitation. (crates/tinycomputer-browser/src/origins/origins_tests.rs)
  • integration/behavioral — Session origin checks on the fake engine: navigations refused before being sent, redirects and clicks into refused pages left and reported, drifting pages never acted on, raw command URL fields checked, fetch-style `read` refused under any list, unreadable-address handling around a navigation commit, and open-time refusal, attached-tab, and leave paths.: Covers the main enforcement paths including the navigation-committed retry window and attached-browser tab handling. (crates/tinycomputer-browser/src/sessions/sessions_tests/origins_tests.rs, crates/tinycomputer-browser/src/sessions/sessions_tests/lifecycle_tests.rs#async fn a_failed_launch_opens_nothing() {)
  • unit — Surface-level origin checks: an observation on a refused page fails as BLOCKED_BY_POLICY without reading it, an admitted page is read as before, and an unreadable address is not read; location grant applies to a kept profile but not an attached endpoint.: Pins the observation-time gate added in the surface operations path and the widened location grant. (crates/tinycomputer-browser/src/surface/surface_tests/origins_tests.rs, crates/tinycomputer-browser/src/surface/surface_tests/operations_tests.rs#fn location_is_granted_only_in_a_browser_the_module_launched() {)
  • integration/behavioral — Cover dismissal and uncovered-press flow on the simulator: an empty backdrop pressed outside and the target retried, stubborn or fleeting layers handled, a control over the target never pressed and named in the failure note; plus constraint validation refusals and a no-rescue path for an unstartable browser.: Covers the new dismiss_cover surface method end to end through the flow, including that nothing exposed by a dismissal is pressed without re-grounding. (crates/tinycomputer-engine/src/agentic/flow/flow_tests/do_loop_tests.rs#async fn a_covered_click_closes_what_covers_it_and_tries_again() {, crates/tinycomputer-browser/src/surface/surface_tests/cover_tests.rs, crates/tinycomputer-engine/src/task/task_tests/start_tests.rs#async fn a_value_supplied_for_a_missing_fact_still_fails_fast_if_it_leaks() {, crates/tinycomputer-engine/src/task/task_tests/rescue_tests.rs#async fn walls_budgets_and_run_errors_are_never_rescued() {)

Findings

  • critical · critique · Add the cover tests module before declaring it — This declaration requires `cover_tests.rs` or `cover_tests/mod.rs`, but neither module exists in the repository. Rust will fail compilation with a missing module error; add the mod (crates/tinycomputer\-browser/src/surface/surface\_tests\.rs:18)
  • critical · critique · Add the origins module before declaring it — This declaration requires `origins_tests.rs` or `origins_tests/mod.rs`, but neither module exists in the repository. Rust will fail compilation with a missing module error; add the (crates/tinycomputer\-browser/src/surface/surface\_tests\.rs:22)
  • critical · critique · Add the declared test modules before compiling — Neither `live_cover_tests.rs` nor `live_day_label_tests.rs` exists at this commit, so these declarations produce Rust module-not-found errors and break the build for every caller. (crates/tinycomputer\-browser/src/surface/sight/sight\_tests\.rs:8)
  • critical · critique · Map the timeout error before constructing the browser error — The `devtools url` check runs before the timeout check, so a message such as `Timeout waiting for Chrome DevTools URL` is classified as `BrowserUnavailable` and never reaches `Erro (crates/tinycomputer\-browser/src/reply/mod\.rs:70)
  • high · critique · Treat an empty point beneath the cover as non-pressable — `pressable` is meant to identify things that would receive a meaningful press beneath the cover, but `!node` returns `true`. For a full-screen backdrop over an otherwise empty part (crates/tinycomputer\-browser/src/surface/cover\.rs:95)
  • high · critique · Reject public names that resolve to local addresses — This explicitly documents a DNS-rebinding/SSRF bypass: a hostname that is publicly named but resolves to `127.0.0.1`, a private RFC1918 address, or another local address is admitte (docs/technical/tasks\.md)
  • high · critique · Apply the origin policy to external resource loads — This states that scripts and other resources can be fetched from hosts outside the admitted origins, including private or local hosts. A permitted page can consequently cause netwo (docs/technical/tasks\.md)
  • high · critique · Do not bypass origin checks on navigation errors — A navigation can leave the page at a refused origin while the browser temporarily reports errors such as `execution context was destroyed`. This branch treats those errors as succe (crates/tinycomputer\-browser/src/sessions/mod\.rs:169)
  • high · critique · Preserve compatibility for relative browser profiles — This changes the documented contract so every existing caller that supplies a relative profile path now receives `INVALID_REQUEST`. Unless the API version intentionally makes a bre (docs/technical/tasks\.md)
  • high · critique · Validate permission-grant origins before sending the command — The admission loop only examines `url`, `url1`, and `url2`. A raw permission-grant command can carry its target in an `origin` field, so a command such as `{"action":"grant_permiss (crates/tinycomputer\-browser/src/sessions/page\.rs:207)
  • medium · critique · Do not claim cart headers never identify items — Some cart buttons expose item identity through a mini-cart, accessible name, tooltip, or expanded preview rather than only a count. Telling the agent that the header can never show (crates/tinycomputer\-bus/src/flow/guide\.md)
  • medium · critique · Preserve front state when a refused press can still land — `refused` treats every `NOT_ACTIONABLE` response as proof that no input reached the page, but the new comment explicitly documents an exception: a result card's cover can cause the (crates/tinycomputer\-engine/src/agentic/flow/action\.rs:44)
  • medium · critique · Describe nested text in empty-layer detection accurately — The implementation only checks direct text nodes of the element at the hit point (`[...hit.childNodes]`), not text in descendants. An overlay such as `<div><span>Loading</span></di (docs/crates/tinycomputer\-browser/interacting\.md:122)
  • medium · critique · Document the refused-press exception — `NOT_ACTIONABLE` is not guaranteed to mean that the press never reached the page. The action contract explicitly allows a result-card cover case where the final mouse event reaches (docs/crates/tinycomputer\-engine/flow/the\-do\-loop\.md:105)
  • medium · critique · Preserve the control obstruction during cover dismissal — `ControlOver` deliberately returns a covered error for the target, but `dismiss_cover` only distinguishes `StubbornBackdrop` and `Backdrop`; for this quirk it falls through to `{"d (crates/tinycomputer\-engine/src/agentic/flow/flow\_tests/simulator\.rs:369)
  • medium · critique · Wait for navigation to settle before returning results — `check_if_readable(true)` deliberately treats an address-read failure caused by an in-progress navigation as success. A command such as `evaluate` can set `location.href` to a refu (crates/tinycomputer\-browser/src/sessions/page\.rs:252)
  • critical · security · Add the cover tests module before declaring it — This declaration requires `crates/tinycomputer-browser/src/surface/cover_tests.rs` (or an equivalent module directory), but no such source file is present. Rust will fail compilati (crates/tinycomputer\-browser/src/surface/surface\_tests\.rs:18)
  • critical · security · Add the origins tests module before declaring it — This declaration requires `crates/tinycomputer-browser/src/surface/origins_tests.rs` (or an equivalent module directory), but no such source file is present. Rust will fail compila (crates/tinycomputer\-browser/src/surface/surface\_tests\.rs:22)
  • critical · security · Add the declared test module source files — These module declarations have no corresponding `live_cover_tests.rs` or `live_day_label_tests.rs` in the repository, so Rust fails module resolution when compiling the test target (crates/tinycomputer\-browser/src/surface/sight/sight\_tests\.rs:8)
  • high · security · Check refused pages before running every raw command — The new `dismiss_cover` operation directly invokes `press_cover` without checking the current page against `allowed_origins`. Callers can use this operation after navigation or a r (crates/tinycomputer\-browser/src/surface/operations\.rs:329)
  • high · security · Block permission grants in persistent profiles — Checking that the current page is admitted does not prevent a raw permission command from permanently changing a persistent browser profile. A caller can therefore grant location o (crates/tinycomputer\-browser/src/sessions/page\.rs:117)
  • medium · security · Assert every routing operation succeeds — The new test discards the responses from all three operations, so it would still pass if an operation returned an error as long as the recorder observed the call. Assert each respo (crates/tinycomputer\-engine/src/workspace/workspace\_tests\.rs:261)
  • medium · security · Hold the session lock through the policy-protected operation — `check_page` validates the current page while briefly holding the session lock, but the lock is released before `see` or `snapshot` runs. A navigation can therefore replace the adm (crates/tinycomputer\-browser/src/surface/operations\.rs:35)

Resolved this pass

  • Canonicalize hosts before comparing them
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Reject IPv6 site-local addresses
  • Check the initial page before exposing the session
  • Provide the response needed to read the admitted page
  • Check the page before allowing subsequent typed operations
  • Propagate all page-check errors
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Check page-reading commands before returning their data
  • Check raw page observations before returning their data
  • Assert the specific attached-session failure
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Add the declared origins test module
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Do not expose the browser executable to model input
  • Make the opener fixture represent its claimed nesting
  • Normalize alternate IPv4 forms before comparing hosts
  • Restrict browser profiles to trusted host configuration
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Restrict month detection to the active calendar
  • Apply origin policy to external script loads
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually a browser binary
  • Check raw page observations before returning their data
  • Apply the origin policy to external resource loads
  • Gate permission changes with the origin policy
  • Check refused pages before running every raw command
  • high — Restrict month detection to the active calendar
  • high — Restrict month-heading detection to the active calendar
  • high — Tie heading evidence to the active calendar
  • medium — Accept a weekday header plus six calendar weeks
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Add the declared origins test module
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Do not expose the browser executable to model input
  • Make the opener fixture represent its claimed nesting
  • Normalize alternate IPv4 forms before comparing hosts
  • Restrict browser profiles to trusted host configuration
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Restrict month detection to the active calendar
  • Use an actual browser binary in the executable test
  • Apply origin policy to external script loads
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually a browser binary
  • Check raw page observations before returning their data
  • Apply the origin policy to external resource loads
  • Gate permission changes with the origin policy
  • Check refused pages before running every raw command
  • Assert every runner operation succeeds or fails as intended
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Add the declared origins test module
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Make the opener fixture represent its claimed nesting
  • Normalize alternate IPv4 forms before comparing hosts
  • Restrict browser profiles to trusted host configuration
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Apply origin policy to external script loads
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually a browser binary
  • Check raw page observations before returning their data
  • Apply the origin policy to external resource loads
  • Gate permission changes with the origin policy
  • Check refused pages before running every raw command
  • Assert every runner operation succeeds or fails as intended
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Add the declared origins test module
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Make the opener fixture represent its claimed nesting
  • Normalize alternate IPv4 forms before comparing hosts
  • Restrict browser profiles to trusted host configuration
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Restrict month detection to the active calendar
  • Use an actual browser binary in the executable test
  • Apply origin policy to external script loads
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually a browser binary
  • Check raw page observations before returning their data
  • Apply the origin policy to external resource loads
  • Gate permission changes with the origin policy
  • Check refused pages before running every raw command
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Make the opener fixture represent its claimed nesting
  • Normalize alternate IPv4 forms before comparing hosts
  • Restrict browser profiles to trusted host configuration
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Restrict month detection to the active calendar
  • Use an actual browser binary in the executable test
  • Apply origin policy to external script loads
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually a browser binary
  • Check raw page observations before returning their data
  • Apply the origin policy to external resource loads
  • Gate permission changes with the origin policy
  • Check refused pages before running every raw command
  • Remove the claim that agent-browser filters subresource requests
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Reject IPv6 site-local addresses
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Hold the session lock through the policy-protected operation
  • Check page-reading commands before returning their data
  • Check pushstate URLs before sending the command
  • Gate permission changes with the origin policy
  • Check refused pages before running every raw command
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Add the declared origins test module
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Do not expose the browser executable to model input
  • Make the opener fixture represent its claimed nesting
  • Normalize alternate IPv4 forms before comparing hosts
  • Restrict browser profiles to trusted host configuration
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Restrict month detection to the active calendar
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Apply origin policy to external script loads
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually a browser binary
  • Check raw page observations before returning their data
  • Apply the origin policy to external resource loads
  • Gate permission changes with the origin policy
  • Check refused pages before running every raw command
  • Remove the claim that agent-browser filters subresource requests
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Add the declared origins test module
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Do not expose the browser executable to model input
  • Make the opener fixture represent its claimed nesting
  • Normalize alternate IPv4 forms before comparing hosts
  • Restrict browser profiles to trusted host configuration
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Restrict month detection to the active calendar
  • Check pushstate URLs before sending the command
  • Apply origin policy to external script loads
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually a browser binary
  • Check raw page observations before returning their data
  • Apply the origin policy to external resource loads
  • Gate permission changes with the origin policy
  • Check refused pages before running every raw command
  • Enforce the origin policy before returning a new session
  • Check the initial page before exposing the session
  • Admit the newly opened attached page before returning
  • Verify the page after leaving a refused launch
  • Hold the session lock through the policy-protected operation
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Add the declared origins test module
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Do not expose the browser executable to model input
  • Make the opener fixture represent its claimed nesting
  • Normalize alternate IPv4 forms before comparing hosts
  • Restrict browser profiles to trusted host configuration
  • Verify the page after leaving a refused launch
  • Check page-reading commands before returning their data
  • Restrict month detection to the active calendar
  • Validate that the executable is actually launchable
  • Check pushstate URLs before sending the command
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually a browser binary
  • Apply origin policy to external script loads
  • Restrict month-heading detection to the active calendar
  • Apply the origin policy to external resource loads
  • Hold the session lock through the policy-protected operation
  • Check refused pages before running every raw command
  • Assert every runner operation succeeds or fails as intended
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Add the declared origins test module
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Make the opener fixture represent its claimed nesting
  • Normalize alternate IPv4 forms before comparing hosts
  • Restrict browser profiles to trusted host configuration
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Apply origin policy to external script loads
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually a browser binary
  • Check raw page observations before returning their data
  • Apply the origin policy to external resource loads
  • Gate permission changes with the origin policy
  • Check refused pages before running every raw command
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Add the declared origins test module
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Do not expose the browser executable to model input
  • Make the opener fixture represent its claimed nesting
  • Normalize alternate IPv4 forms before comparing hosts
  • Preserve compatibility for relative browser profiles
  • Restrict browser profiles to trusted host configuration
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Restrict month detection to the active calendar
  • Apply origin policy to external script loads
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually a browser binary
  • Check raw page observations before returning their data
  • Apply the origin policy to external resource loads
  • Gate permission changes with the origin policy
  • Check refused pages before running every raw command
  • Propagate page-check failures instead of failing open
  • Restrict the browser executable before launching it
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Make the opener test match the implemented ranking
  • Restrict the browser executable to trusted host configuration
  • Make the opener fixture represent its claimed nesting
  • Preserve compatibility for relative browser profiles
  • Restrict browser profiles to trusted host configuration
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Validate that the executable is actually launchable
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Do not expose the browser executable to model input
  • Check page-reading commands before returning their data
  • Apply origin policy to external script loads
  • Gate permission changes with the origin policy
  • Check raw page observations before returning their data
  • Apply the origin policy to external resource loads
  • Check refused pages before running every raw command
  • Hold the session lock through the policy-protected operation
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Provide the response needed to read the admitted page
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Preserve compatibility for relative browser profiles
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Canonicalize hosts before comparing them
  • Normalize alternate IPv4 forms before allowing public hosts
  • Reject non-canonical IPv4 host forms
  • Parse URLs with the browser's URL parser
  • Reject IPv6 site-local addresses
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Restrict month-heading detection to the active calendar
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Restrict month-heading detection to the active calendar
  • Propagate page-check failures instead of failing open
  • Check the initial page before exposing the session
  • Check raw page observations before returning their data
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Reject non-canonical IPv4 host forms
  • Parse URLs with the browser's URL parser
  • Reject IPv6 site-local addresses
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Restrict month-heading detection to the active calendar
  • Check pushstate URLs before sending the command
  • Add the declared origins test module
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Do not expose the browser executable to model input
  • Make the opener fixture represent its claimed nesting
  • Parse URLs with the browser's URL parser
  • Normalize alternate IPv4 forms before comparing hosts
  • Preserve compatibility for relative browser profiles
  • Restrict browser profiles to trusted host configuration
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Preserve compatibility for relative browser profiles
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Preserve compatibility for relative browser profiles
  • Restrict month detection to the active calendar
  • Do not grant location permission in persistent profiles
  • Use an actual browser binary in the executable test
  • Use an actual browser binary in the executable test
  • Check pushstate URLs before sending the command
  • Apply origin policy to external script loads
  • Restrict month-heading detection to the active calendar
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Propagate page-check failures instead of failing open
  • Propagate page-check failures instead of failing open
  • Assert the specific attached-session failure
  • Reject public names that resolve to private addresses
  • Validate that the executable is actually a browser binary
  • Parse URLs with the browser's URL parser
  • Preserve compatibility for relative browser profiles
  • Restrict browser profiles to trusted host configuration
  • Restrict the browser executable to trusted host configuration
  • Check raw page observations before returning their data
  • Apply the origin policy to external resource loads
  • Restrict browser profiles to trusted host configuration
  • Gate permission changes with the origin policy
  • Hold the session lock through the policy-protected operation
  • Check refused pages before running every raw command
  • Assert every runner operation succeeds or fails as intended
  • High — Restrict month-heading detection to the active calendar
  • High — Restrict month detection to the active calendar
  • Critical — Base completion on the selected date
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Add the declared origins test module
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Do not expose the browser executable to model input
  • Make the opener fixture represent its claimed nesting
  • Normalize alternate IPv4 forms before comparing hosts
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Restrict month detection to the active calendar
  • Use an actual browser binary in the executable test
  • Apply origin policy to external script loads
  • Restrict month-heading detection to the active calendar
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually a browser binary
  • Apply the origin policy to external resource loads
  • Gate permission changes with the origin policy
  • Check refused pages before running every raw command
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Reject non-canonical IPv4 host forms
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Do not expose the browser executable to model input
  • Make the opener fixture represent its claimed nesting
  • Reject public names that resolve to private addresses
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Verify the page after leaving a refused launch
  • Do not grant location permission in persistent profiles
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Validate that the executable is actually launchable
  • Restrict month detection to the active calendar
  • Apply origin policy to external script loads
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually a browser binary
  • Apply the origin policy to external resource loads
  • Gate permission changes with the origin policy
  • Check refused pages before running every raw command
  • Canonicalize hosts before comparing them
  • Check the page before allowing subsequent typed operations
  • Preserve compatibility for relative browser profiles
  • Enforce the origin policy before returning a new session
  • Normalize alternate IPv4 forms before allowing public hosts
  • Parse URLs with the browser's URL parser
  • Keep the schema example valid JSON
  • Check the initial page before exposing the session
  • Propagate all page-check errors
  • Remove the claim that agent-browser filters subresource requests
  • Reject IPv6 site-local addresses
  • Assert every runner operation succeeds or fails as intended
  • Preserve coverage for allowed-origin handling
  • Hold the session lock through the policy-protected operation
  • Provide the response needed to read the admitted page
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Use only a wildcard when testing missing payment origins
  • Restrict the browser executable before launching it
  • Make the opener test match the implemented ranking
  • Restrict month-heading detection to the active calendar
  • Accept a weekday header plus six calendar weeks
  • Assert that the calendar flow run succeeds
  • Map the timeout error before constructing the browser error
  • Use an actual browser binary in the executable test
  • Check the page before returning its title
  • Reject public names that resolve to private addresses
  • Check the page before running typed observations
  • Check pushstate URLs before sending the command
  • Apply origin policy to external script loads
  • Propagate page-check failures instead of failing open
  • Assert the page operation's expected result
  • Assert the specific attached-session failure
  • Validate that the executable is actually launchable
  • Check page-reading commands before returning their data
  • Restrict browser profiles to trusted host configuration
  • Do not grant location permission in persistent profiles
  • Verify the page after leaving a refused launch
  • Base completion on the selected date
  • Tie heading evidence to the active calendar
  • Reject non-canonical IPv4 host forms
  • Test the wildcard payment-origin case in isolation
  • Restrict browser executable to trusted host configuration
  • Do not expose the browser executable to model input
  • Make the opener fixture represent its claimed nesting
  • Admit the newly opened attached page before returning
  • Add the declared origins test module
  • Apply the origin policy to external resource loads
  • Gate permission changes with the origin policy
  • Check raw page observations before returning their data
  • Check refused pages before running every raw command
  • Parse URLs with the browser's URL parser
  • Check the page before allowing subsequent typed operations
  • Check the page before running typed observations
  • Check raw page observations before returning their data
  • Check refused pages before running every raw command
  • Preserve compatibility for relative browser profiles
  • Restrict the browser executable before launching it
  • Restrict browser executable to trusted host configuration
  • Do not expose the browser executable to model input
  • Enforce the origin policy before returning a new session
  • Check the initial page before exposing the session
  • Check the page before returning its title
  • Check pushstate URLs before sending the command
  • Normalize alternate IPv4 forms before allowing public hosts
  • Normalize alternate IPv4 forms before comparing hosts
  • Reject non-canonical IPv4 host forms
  • Reject IPv6 site-local addresses
  • Propagate all page-check errors
  • Propagate page-check failures instead of failing open
  • Add the origins tests module before declaring it
  • Add the origins module before declaring it
  • Add the declared origins test module
  • Admit the newly opened attached page before returning
  • Test the wildcard payment-origin case in isolation
  • Test the wildcard payment-origin case in isolation
  • Use only a wildcard when testing missing payment origins
  • Make the opener test match the implemented ranking
  • Make the opener fixture represent its claimed nesting
  • Restrict month-heading detection to the active calendar
  • Tie heading evidence to the active calendar
  • Restrict month detection to the active calendar
  • Restrict browser profiles to trusted host configuration
  • Do not grant location permission in persistent profiles
  • Verify the page after leaving a refused launch
  • Use an actual browser binary in the executable test
  • Validate that the executable is actually launchable
  • Map the timeout error before constructing the browser error
  • Hold the session lock through the policy-protected operation
  • Preserve coverage for allowed-origin handling
  • Reject public names that resolve to private addresses (documented as a design limit)
  • Canonicalize hosts before comparing them
  • Base completion on the selected date
  • Gate permission changes with the origin policy
  • Apply the origin policy to external resource loads

Before merge

  • Address Add the cover tests module before declaring it (crates/tinycomputer\-browser/src/surface/surface\_tests\.rs).
  • Address Add the origins module before declaring it (crates/tinycomputer\-browser/src/surface/surface\_tests\.rs).
  • Address Add the declared test modules before compiling (crates/tinycomputer\-browser/src/surface/sight/sight\_tests\.rs).
  • Address Map the timeout error before constructing the browser error (crates/tinycomputer\-browser/src/reply/mod\.rs).
  • Address Treat an empty point beneath the cover as non-pressable (crates/tinycomputer\-browser/src/surface/cover\.rs).
  • Address Reject public names that resolve to local addresses (docs/technical/tasks\.md).
  • Address Apply the origin policy to external resource loads (docs/technical/tasks\.md).
  • Address Do not bypass origin checks on navigation errors (crates/tinycomputer\-browser/src/sessions/mod\.rs).
  • Address Preserve compatibility for relative browser profiles (docs/technical/tasks\.md).
  • Address Validate permission-grant origins before sending the command (crates/tinycomputer\-browser/src/sessions/page\.rs).
  • Address Add the cover tests module before declaring it (crates/tinycomputer\-browser/src/surface/surface\_tests\.rs).
  • Address Add the origins tests module before declaring it (crates/tinycomputer\-browser/src/surface/surface\_tests\.rs).
  • Address Add the declared test module source files (crates/tinycomputer\-browser/src/surface/sight/sight\_tests\.rs).
  • Address Check refused pages before running every raw command (crates/tinycomputer\-browser/src/surface/operations\.rs).
  • Address Block permission grants in persistent profiles (crates/tinycomputer\-browser/src/sessions/page\.rs).

How this fits together

flowchart LR
  n0["every_variant<br/>changed"]:::changed
  n1["Error<br/>changed"]:::changed
  n0 -->|uses| n1
  classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
  classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
  classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
  classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Loading
Agent review details

critique

  • Conclusion: Failure
  • Scope reviewed: all assigned evidence
  • Positive: Page URLs are now parsed with the browser's own URL rules, closing the alternate-encoding bypasses (decimal IPs, percent escapes, full-width digits, backslashes) earlier review rounds flagged.
  • Positive: Session open refuses to hand out a session on a refused page it cannot leave, closing the earlier fail-open concern at launch time.
  • Lane summary: Reviewed 50 files; 23 findings. (4 already reported on an earlier push) (1 earlier finding(s) still open) (3 observation(s) grouped into shared inline comments) (+3 more not shown) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinycomputer\-browser/src/surface/surface\_tests\.rs — Add the cover tests module before declaring it
  • Evidence: crates/tinycomputer\-browser/src/surface/surface\_tests\.rs — Add the origins module before declaring it
  • Evidence: crates/tinycomputer\-browser/src/surface/sight/sight\_tests\.rs — Add the declared test modules before compiling
  • Evidence: crates/tinycomputer\-browser/src/reply/mod\.rs — Map the timeout error before constructing the browser error
  • Evidence: crates/tinycomputer\-browser/src/surface/cover\.rs — Treat an empty point beneath the cover as non-pressable
  • Evidence: docs/technical/tasks\.md — Reject public names that resolve to local addresses
  • Evidence: docs/technical/tasks\.md — Apply the origin policy to external resource loads
  • Evidence: crates/tinycomputer\-browser/src/sessions/mod\.rs — Do not bypass origin checks on navigation errors
  • Evidence: docs/technical/tasks\.md — Preserve compatibility for relative browser profiles
  • Evidence: crates/tinycomputer\-browser/src/sessions/page\.rs — Validate permission-grant origins before sending the command
  • Evidence: crates/tinycomputer\-bus/src/flow/guide\.md — Do not claim cart headers never identify items
  • Evidence: crates/tinycomputer\-engine/src/agentic/flow/action\.rs — Preserve front state when a refused press can still land
  • Evidence: docs/crates/tinycomputer\-browser/interacting\.md — Describe nested text in empty-layer detection accurately
  • Evidence: docs/crates/tinycomputer\-engine/flow/the\-do\-loop\.md — Document the refused-press exception
  • Evidence: crates/tinycomputer\-engine/src/agentic/flow/flow\_tests/simulator\.rs — Preserve the control obstruction during cover dismissal
  • Evidence: crates/tinycomputer\-browser/src/sessions/page\.rs — Wait for navigation to settle before returning results

security

  • Conclusion: Failure
  • Scope reviewed: all assigned evidence
  • Positive: Host-only settings (browser_executable, browser_profile) are kept out of model-facing schemas, matching the trusted-configuration concern about executable and profile paths.
  • Positive: Raw commands are checked both for URL-naming fields and for the page shown before and after, addressing the raw-command authorization-bypass finding from earlier rounds; the fetch-style `read` is refused under any list because it follows redirects where no page is checked.
  • Lane summary: Reviewed 37 files; 9 findings. 13 files were not security-reviewed: crates/tinycomputer-bus/src/flow/guide.md (prose or tabular data), docs/crates/tinycomputer-browser/errors.md (prose or tabular data), docs/crates/tinycomputer-browser/interacting.md (prose or tabular data), docs/crates/tinycomputer-browser/sessions.md (prose or tabular data), docs/crates/tinycomputer-browser/sight.md (prose or tabular data), and 8 more. (2 already reported on an earlier push) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinycomputer\-browser/src/surface/surface\_tests\.rs — Add the cover tests module before declaring it
  • Evidence: crates/tinycomputer\-browser/src/surface/surface\_tests\.rs — Add the origins tests module before declaring it
  • Evidence: crates/tinycomputer\-browser/src/surface/sight/sight\_tests\.rs — Add the declared test module source files
  • Evidence: crates/tinycomputer\-browser/src/surface/operations\.rs — Check refused pages before running every raw command
  • Evidence: crates/tinycomputer\-browser/src/sessions/page\.rs — Block permission grants in persistent profiles
  • Evidence: crates/tinycomputer\-engine/src/workspace/workspace\_tests\.rs — Assert every routing operation succeeds
  • Evidence: crates/tinycomputer\-browser/src/surface/operations\.rs — Hold the session lock through the policy-protected operation

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: All prior findings from earlier review rounds are addressed in this revision, including URL canonicalisation tests, pre-delivery checks, host-only browser settings, opener ranking, heading detection, and schema parity; no new findings were raised by that lane.
  • Lane summary: The change moves the origin allow-list out of agent-browser into the session (WHATWG URL parsing, `*` for public hosts, per-call page checks with `LeftRefusedPage` for calls that ran), adds host-set browser executable/profile constraints with validation, and extends the flow with cover dismissal, bare-calendar paging, and launch-failure reporting. The earlier review's concerns are addressed in this revision: the origins module and its tests now exist, URLs are parsed with the `url` crate including alternate IPv4 forms, IPv6 site-local and NAT64/6to4 forms are covered, sessions are locked across policy-checked operations, the initial and attached pages are checked before the session is handed out, pushstate and route patterns are exempted with justification, `*` is refused for `fill_then_approve`, the executable must be an absolute launchable file, and the schema and skill leave the host's settings out — each with tests that would fail on regression. The one deliberate limitation, that public names resolving to local addresses are admitted, is documented as the guard-rail boundary rather than claimed as enforced. Nothing new stands; this looks safe to merge. (4 earlier finding(s) still open) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._

commits

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: Nothing sensitive found in what this pull request commits.

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The remaining design trade-offs (files a page loads are unfiltered, DNS is never resolved, any executable file passes as the browser binary) are documented as intended guard-rail boundaries rather than claimed as enforced.
  • Lane summary: The final revision closes out the review's hardening round: pages are parsed with the browser's URL rules and checked around every acting or reading call, `LeftRefusedPage` separates a refusal after work from one before it, opening fails closed on an unleaveable first page, the browser binary and profile are validated as host-only settings and kept out of every model-facing schema, the contract bump to 2.10 is deliberate and documented, and the date-form and opener fixes are backed by tests. The remaining design trade-offs (files a page loads are unfiltered, DNS is never resolved, any executable file passes as the browser binary) are documented as intended behavior. Nothing new blocks the merge. (14 earlier finding(s) still open) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._

e2e

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: No end-to-end harness in this repository: no e2e test files and no e2e workflow.
Evidence and run details
  • Models: gpt-5.6-luna, glm-5.3-flash
  • Spend: $0.036820
  • Tokens: 2755507 input · 198009 output · 216786 cached · 0 embedding
  • Continuity: summary cache chain restarted at the storage ceiling.
Head State Pass summary
1438fe024b7e changes requested 7 active finding(s), 146 resolved finding(s) (at 1791564526)
c8b39c6398d2 changes requested 26 active finding(s), 499 resolved finding(s) (at 1791567331)
91e8274ec529 changes requested 20 active finding(s), 446 resolved finding(s) (at 1791568134)
d3789d1656b3 changes requested 13 active finding(s), 454 resolved finding(s) (at 1791569787)
b06b7bc7bf2a changes requested 23 active finding(s), 912 resolved finding(s) (at 1791576212)

tinysweeper 0.1.0

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9a805109-f754-48dc-a8b4-81af17f19575

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 2 lane(s) blocking, worst finding is critical.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0158 · 1,260,334 in / 79,390 out · 139,511 cached (11%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0093 · 731,311 in   / 45,170 out · 81,838 cached (11%)  · gpt-5.6-luna, glm-5.3-flash
security:    $0.0055 · 424,997 in   / 26,959 out · 55,689 cached (13%)  · gpt-5.6-luna
tests:       $0.0005 · 51,323 in    / 4,839 out  · 1,856 cached (4%)    · glm-5.3-flash
description: $0.0002 · 25,332 in    / 456 out    · 64 cached (0%)       · glm-5.3-flash

Comment thread crates/tinycomputer-browser/src/origins/mod.rs Outdated
Comment thread crates/tinycomputer-browser/src/sessions/page.rs Outdated
Comment thread crates/tinycomputer-engine/src/task/controller.rs Outdated
Comment thread crates/tinycomputer-browser/src/sessions/mod.rs
Comment thread crates/tinycomputer-browser/src/origins/mod.rs Outdated
Comment thread crates/tinycomputer-browser/src/sessions/sessions_tests.rs
Comment thread crates/tinycomputer-browser/src/lib.rs
Comment thread crates/tinycomputer-engine/src/task/task_tests/start_tests.rs Outdated
Comment thread crates/tinycomputer/src/tinybus_module/runner.rs
Comment thread crates/tinycomputer-browser/src/origins/mod.rs Outdated
A month drawn as its weeks (four to six rows of up to seven days, as
React-style pickers draw it) is read as the run of its days, like a flat
grid. A day is described by its date unless the page's own label for it
names the month; a label that names none ("Sold out") follows the date.
A grid's title is never taken from inside a calendar found before it.

Live, a hotel site's open days showed a number and a fare in week rows:
none read as a date, and the date step paged a year past October.
Paging a calendar to a date now also stops when text on screen heads the
wanted month: only months, years, and day names ("October 2026", "Oct
2026 Mo Tu We ... November 2026"). A day number or any other word makes
it a date or a sentence, never a heading.

Days that show only a number and a fare name no month, so no day ever
matched and the calendar was paged to the 12-month limit, twice.
Of several controls whose label holds a slot's word, the opener is the
one holding it soonest, then the one with the fewest words: a control
wrapping others names them all.

Live, for the slot "from city" a trip-type tab "Multi City" came first
and was refused; the do loop then pressed the button wrapping the whole
form at its centre, twice, and picked a return date that turned a
one-way search into a round trip.
@YellowSnnowmann YellowSnnowmann changed the title Check allowed origins on pages, and let a task name its browser and profile Check origins on pages, let a task name its browser, fix date-form picks Oct 9, 2026

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 2 lane(s) blocking, worst finding is critical.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0090 · 695,133 in / 54,453 out · 62,799 cached (9%)  · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0047 · 339,591 in / 28,244 out · 40,717 cached (12%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0029 · 206,343 in / 15,085 out · 21,826 cached (11%) · gpt-5.6-luna
tests:       $0.0007 · 74,818 in  / 6,663 out  · 128 cached (0%)     · glm-5.3-flash
description: $0.0003 · 35,767 in  / 1,416 out  · 64 cached (0%)      · glm-5.3-flash

Comment thread crates/tinycomputer-engine/src/agentic/flow/flow_tests/enter_tests.rs Outdated
Comment thread crates/tinycomputer-engine/src/agentic/flow/steps/reveal.rs Outdated
Comment thread crates/tinycomputer-browser/src/surface/sight/sight.js Outdated
Comment thread crates/tinycomputer-browser/src/origins/mod.rs Outdated
Comment thread crates/tinycomputer-browser/src/origins/mod.rs Outdated
Comment thread crates/tinycomputer-browser/src/origins/mod.rs
The session read a page's address with its own string rules, and judged
hosts the browser never opened: `http://2130706433/`, `127.1`, hex and
octal forms, percent-escaped or full-width digits, `http:\\127.0.0.1\`,
and `https://evil.test\@example.com/` (read as example.com; Chrome opens
evil.test). Addresses are now parsed with the `url` crate, which follows
the WHATWG rules Chrome does, and hosts are compared canonically.

Under `*`, IPv4 carried in IPv6 (compatible, NAT64, 6to4) is judged as
itself, site-local fec0::/10 is non-global, and single-label names and
names under internal and home.arpa are local. Only about:blank and
about:srcdoc pass among about: pages (about:settings is a browser page),
and a blob: page passes when the site that made it does.
A page that moved out of the allowed origins on its own (a timer, a
redirect after a raw command) could still be acted on or read: `perform`
sent its action before checking, `evaluate`, `screenshot`, and raw
commands never checked, and the first page of a session was taken as is.

Now every call that acts on or reads the page checks it first, and a raw
command or script checks the page it leaves before returning anything.
A raw command naming an address in `url`, `url1`, or `url2` is checked
like a navigation, a raw `read` of an address (which follows redirects
unseen) is refused under a list, and raw waits and lookups that neither
act nor read go unchecked, so a wait runs while a navigation commits. A
page whose address cannot be read around a call's own work lets it go
ahead; the observation's check reads twice, fails closed, is bounded by
READ_TIMEOUT, and runs only under a list. A navigation reads the page it
reached afresh. A refused first page is left; an attached browser keeps
the person's tab and opens one of the session's own.

A page refused after the call ran is `LeftRefusedPage`: the same
BLOCKED_BY_POLICY code, but its delivery is unknown, since the click that
reached it may have paid. Docs say what the list covers, what it does
not (names are never resolved), and where card details may be typed.
`browser_executable` and `browser_profile` are host settings, but the
agent-facing skill schema offered them, so a host relaying a model's
constraints could let page text pick the binary that launches.

A task now starts only with a binary given as the absolute path of an
existing file (no name looked up on PATH, no folder) and a profile given
as an absolute folder, each taken exactly as written, and with neither
beside `browser_endpoint`, which launches nothing; agent-browser refused
that pair only at the first browser step. The skill schema and SKILL.md
leave both out, Describe marks them the host's, and the docs say a host
never takes them from a model and must cancel a task still holding a
profile before starting another on it. The skill and Describe also say
that `fill_then_approve` refuses `*`, and the versioning guide shows the
current contract version.
The location grant stood back whenever a browser had a profile folder,
taking it for a person's own. Since a task may now keep a profile
between its runs, that browser is still one the module launched, and a
headless task pressing a store's "use my current location" waited on a
bubble no one could answer. The grant now stands back only for a
person's running browser (an endpoint); it lasts while the browser runs
and is not written into the profile.
A header naming two months gave them to the grids it titled in the
order they were found, so a missed grid (a "Today" over its first day, a
hidden week) gave the next month's days the month before's name. Week
rows made that reachable, and a wrong date is worse than none: grids are
now dated only when every month of their header found its grid, and
stay calendars, undated, otherwise. A page's own label that names a month
stands alone, never behind a computed date.

A calendar found before a grid is passed over again, so a second grid of
bare numbers still reaches its header, but a header beyond it titles the
grid only while it has a month left. Week rows may be seven (a row of
day names before six weeks), cheap tests run before reading cell text,
and a month name is matched as a whole word.
Any month-and-year text anywhere on the page stopped the paging, so a
month menu, a strip of month tabs, or a list grouped by month could strand
a dated calendar on the wrong month. The heading now counts only when it
sits within HEADING_REACH (8) nodes of the very "next month" arrow, is no
choice of month (an option, a tab, a menu item), and at least BARE_DAYS
(7) days on screen show bare numbers; a calendar whose days name their
month is paged by them alone. The paging test now asserts the step's
outcome as well: an undated day is never pressed on its number.
Ranking by the fewest words made any short control sharing a slot's
word beat its box: "Date Change" for "departure date", "City Guides"
for "from city". Openers now rank by being on screen, then holding more
of the slot's words, then holding its first (most particular) word, then
wrapping no other match, with document order deciding the rest, as the
first match did before.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 2 lane(s) blocking, worst finding is critical.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0338 · 2,427,145 in / 215,207 out · 276,599 cached (11%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0209 · 1,521,158 in / 132,079 out · 192,054 cached (13%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0112 · 723,176 in   / 75,993 out  · 84,353 cached (12%)  · gpt-5.6-luna
tests:       $0.0006 · 58,697 in    / 1,993 out   · 0 cached (0%)        · glm-5.3-flash
description: $0.0005 · 59,505 in    / 1,680 out   · 64 cached (0%)       · glm-5.3-flash

Comment thread crates/tinycomputer-browser/src/surface/operations.rs
Comment thread crates/tinycomputer-engine/src/task/task_tests/start_tests.rs
Comment thread crates/tinycomputer-browser/src/sessions/page.rs Outdated
Comment thread docs/technical/tasks.md
Comment thread crates/tinycomputer-browser/src/sessions/page.rs
Comment thread crates/tinycomputer-engine/src/task/controller.rs
Comment thread crates/tinycomputer-bus/src/agent/types/request.rs
Comment thread crates/tinycomputer-browser/src/sessions/mod.rs Outdated
Comment thread crates/tinycomputer-browser/src/surface/location.rs
Comment thread crates/tinycomputer-engine/src/task/task_tests/start_tests.rs
`snapshot`, `read_page`, and `screenshot` checked only the page they left,
so a read still ran on a page that had moved out of the allowed origins;
they now check first too, as actions do, and a raw `title` (a read of what
the page shows) no longer skips the check. Opening a session no longer
hands one out on a refused page: an attached browser whose own tab cannot
be opened fails the open, and a launched one whose first page cannot be
left is closed, and the open fails BlockedByPolicy.
Any seven clickable numbers anywhere on the page (a results list's page
numbers) counted as a calendar's bare days. Only those within DAYS_REACH
(100) nodes of the arrow about to be pressed count now: two months' cells,
their day names, and their headings.
Describe is what a model reads, and it still listed `browser_executable`
and `browser_profile`, marked as the host's. They are left out now, as in
the skill, and the parity test names them as the host's own settings kept
out on purpose. The payment test also checks `*` alone, not only beside a
named site, and the binary test says why any existing file passes.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 2 lane(s) blocking, worst finding is critical.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0132 · 999,174 in / 83,985 out · 110,476 cached (11%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0069 · 503,590 in / 43,106 out · 69,314 cached (14%)  · gpt-5.6-luna, glm-5.3-flash
security:    $0.0048 · 302,601 in / 33,911 out · 40,906 cached (14%)  · gpt-5.6-luna
tests:       $0.0005 · 61,744 in  / 2,595 out  · 64 cached (0%)       · glm-5.3-flash
description: $0.0005 · 63,596 in  / 1,517 out  · 64 cached (0%)       · glm-5.3-flash

Comment thread crates/tinycomputer-engine/src/agentic/flow/steps/reveal.rs
Comment thread docs/technical/tasks.md
Comment thread crates/tinycomputer-browser/src/sessions/page.rs Outdated
Comment thread docs/technical/tasks.md
Comment thread crates/tinycomputer-browser/src/sessions/mod.rs
Comment thread crates/tinycomputer-browser/src/sessions/sessions_tests/origins_tests.rs Outdated
Comment thread crates/tinycomputer-browser/src/sessions/page.rs
Comment thread crates/tinycomputer-browser/src/sessions/sessions_tests/origins_tests.rs Outdated
A check around a call's own work let the call go ahead on any failure to
read the page's address, so an engine or protocol fault looked like a
readable page. It now lets work go ahead only when the engine says the
page is committing a navigation (its execution context was destroyed),
and fails the call on anything else. `addscript` and `addstyle` put a
caller's chosen file into the page, so their address is checked like a
navigation's. Tests assert the exact failures, and an empty-list assert
uses assert_eq!, as clippy 1.99 asks (CI's Rust job failed on it).
A binary is now refused unless it is an executable file, where files carry
that mark, besides an absolute path to one on this machine, so a readable
file that is no program fails at StartTask rather than at the first
browser step. The browser-setting checks move into a test of their own.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 2 lane(s) blocking, worst finding is critical.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0128 · 984,473 in / 67,989 out · 93,145 cached (9%)  · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0064 · 513,194 in / 34,068 out · 63,395 cached (12%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0043 · 273,894 in / 28,501 out · 26,806 cached (10%) · gpt-5.6-luna
tests:       $0.0005 · 63,268 in  / 1,199 out  · 1,536 cached (2%)   · glm-5.3-flash
description: $0.0005 · 65,250 in  / 1,232 out  · 1,408 cached (2%)   · glm-5.3-flash

Comment thread docs/crates/tinycomputer-browser/sessions.md
Comment thread crates/tinycomputer-engine/src/task/controller.rs
Comment thread docs/crates/tinycomputer-browser/sessions.md
Comment thread crates/tinycomputer-engine/src/task/controller.rs
Comment thread crates/tinycomputer-engine/src/task/controller.rs
Comment thread crates/tinycomputer-browser/src/sessions/page.rs
Comment thread crates/tinycomputer-browser/src/sessions/page.rs
Comment thread crates/tinycomputer-engine/src/task/controller.rs
Comment thread crates/tinycomputer-browser/src/sessions/page.rs Outdated
Comment thread crates/tinycomputer-browser/src/sessions/mod.rs
A day drawn as its number over a fare ("23 6757") that carries its date
only in one inner label ("October 23, 2026") now takes that label as its
date, when the label names a month and the day's number. A month's title
is looked for before the grid or any of its five nearest ancestors, and
the title's own block is a calendar too, so arrows drawn in it page the
month; it is added after the two-month pickers, so no block around a
title and its grid is taken for a picker, and a wizard's "Next" beside
the grid keeps its name.

Live, a flight site's react-calendar drew "‹ October 2026 – November
2026 ›" above both months, outside either, and its priced days carried
their dates only in inner labels: the date step never found a day.
A browser press still refused as covered now says what covers its
target, as a person would (`button "Select Location"`, `an empty layer`),
in the error's details, and whether that is an empty layer a press
outside a popup closes. Covers are read through open shadow roots; a
layer counts as empty only when it shows nothing where it covers the
target, belongs to no component, is placed over the page (fixed or
absolute), covers half the window, and lies over a control sight marked.

The new defaulted `Surface::dismiss_cover` presses such a layer at one
of 49 grid points where the layer itself is on top and nothing pressable
lies beneath (no control, nothing showing a pointer, nothing of the
target), with raw mouse events and the on-screen cursor gliding there.
A control, dialog, text, picture, an unreadable cover, or a layer with
no clear point is never pressed. The desktop refuses it, and the
workspace routes it like `back`.

The flow presses such a layer once after a closer or Escape left the
target covered, looks again, and retries the same vetted target; it
never does so behind a dialog the task opened. The history names the
cover, and a step that fails after a press still refused ends its note
with "its press of … was refused because … lies over it", so a rescue
deals with the cover rather than redo the steps before it. A press the
page refused (`NOT_ACTIONABLE`) never reached it, so it no longer counts
as one that opened a layer in front, or answered one.

The retried press after a cover centres its target at once: a page with
`scroll-behavior: smooth` was still moving it when the press landed.

Live, a store's search box left its suggestions open over the page,
every control outside them read as covered, and Escape left them there.
The basket press was refused, the refused press read as one that opened
a dialog, and the failed step told a rescue to answer it: rescues re-added
other sizes and pressed + again.
A browser the module launches that is not found, or will not start,
now says what to set: "no Chrome or Chromium was found on this machine;
give the path of the browser to use", or, for a binary the session was
given, "the browser binary given could not be started (…); check that
its path names Chrome or Chromium". A binary that is no browser (it
exits before the browser's address shows, or that wait runs out) reads
as a browser that could not be started rather than a timeout or a module
failure. A browser attached to keeps the engine's own words.

An `open` or `browse` step's failure note keeps the first line of the
failure's own words after its code (up to `FAILURE_CHARS`), and a task
step that failed because no browser could be started is never rescued:
the task fails at once, not recoverable, with a hint to give the path of
Chrome or Chromium (`browser_executable`).

Live, a task failed with a bare `https://www.amazon.in could not be
opened: BROWSER_UNAVAILABLE` on a machine whose Chrome was not where it
is looked for, after four rescues that could not have helped
(tinyhumansai/openhuman#7199).
A raw `boundingbox` can test whether a text shows on the page (a
`text=` selector), and a raw `permissions` grant changes what pages may
do, so neither is sent while the session shows a refused page any more:
both now get the check before and after that every call acting on or
reading the page gets. Only a wait for the page to load and a read of its
address, which a refusal names anyway, still go unchecked, so a wait runs
while a navigation commits. The raw command's doc now says exactly that.
The rescuer is told that a failure naming what lies over a refused
press's control names that cover as the screen shows it, its words
screen data: close it, or answer it as the task says when it is the
page's own question the task needs answered, and never redo the steps
before it, which did their work. The flow guide says that a cart button
in a page's header shows only how many items the cart holds, never
which, so a step checks an item went in by its stepper, never by waiting
for the cart button to show it.

Live, a plan waited for "the basket shows Maggi" over a header count
that never could, and rescues of that and of a covered basket press
added more sizes of the item.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 2 lane(s) blocking, worst finding is critical.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0368 · 2,755,507 in / 198,009 out · 216,786 cached (8%)  · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0216 · 1,557,679 in / 123,485 out · 148,741 cached (10%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0127 · 883,749 in   / 66,622 out  · 66,381 cached (8%)   · gpt-5.6-luna
tests:       $0.0008 · 99,978 in    / 1,844 out   · 1,536 cached (2%)    · glm-5.3-flash
description: $0.0008 · 101,767 in   / 2,063 out   · 0 cached (0%)        · glm-5.3-flash

Comment on lines +70 to 75
if lower.contains("devtools url") || lower.starts_with("chrome launch task failed") {
return Error::browser_unavailable(message);
}
if lower.contains("timed out") || lower.contains("timeout") {
return Error::timeout(message, 0);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority critical critique confident

Map the timeout error before constructing the browser error

The devtools url check runs before the timeout check, so a message such as Timeout waiting for Chrome DevTools URL is classified as BrowserUnavailable and never reaches Error::timeout. Callers that distinguish a retryable timeout from a failed browser launch will take the wrong recovery path. Check timeout messages first, then classify the remaining DevTools-launch failures as BrowserUnavailable.

Suggested change
if lower.contains("devtools url") || lower.starts_with("chrome launch task failed") {
return Error::browser_unavailable(message);
}
if lower.contains("timed out") || lower.contains("timeout") {
return Error::timeout(message, 0);
}
if lower.contains("timed out") || lower.contains("timeout") {
return Error::timeout(message, 0);
}
if lower.contains("devtools url") || lower.starts_with("chrome launch task failed") {
return Error::browser_unavailable(message);
}

[RULE] error-classification ·

Comment on lines +95 to +96
const pressable = (node) => !node || Boolean(nearest(node, CONTROL))
|| getComputedStyle(node).cursor === 'pointer' || within(node, target);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high critique confident

Treat an empty point beneath the cover as non-pressable

pressable is meant to identify things that would receive a meaningful press beneath the cover, but !node returns true. For a full-screen backdrop over an otherwise empty part of the page, topAt returns null, so every such spot is considered pressable and press_cover rejects the backdrop even though clicking that empty area is exactly the intended dismissal behavior. Make the predicate require a node before checking the pressable conditions.

Suggested change
const pressable = (node) => !node || Boolean(nearest(node, CONTROL))
|| getComputedStyle(node).cursor === 'pointer' || within(node, target);
const pressable = (node) => Boolean(node) && (Boolean(nearest(node, CONTROL))
|| getComputedStyle(node).cursor === 'pointer' || within(node, target));

[RULE] incorrect-nullability ·

/// The refusal, and a failure to read the address other than a
/// navigation's.
async fn check_if_readable(&mut self, after: bool) -> Result<()> {
match self.check(after).await {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high critique confident

Do not bypass origin checks on navigation errors

A navigation can leave the page at a refused origin while the browser temporarily reports errors such as execution context was destroyed. This branch treats those errors as success and lets the caller perform its operation without knowing the current page; if the follow-up check sees the same transient error, the operation can also return data or perform actions on the refused page. A navigation-related read failure should be retried until the address is known, or the operation should fail without executing while the page is unreadable.

[RULE] fail-open-policy-check ·

let session = self.session(id)?;
let mut session = session.lock().await;
session.run(command).await
if !URL_IS_NO_PAGE.contains(&action) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high critique likely

Validate permission-grant origins before sending the command

The admission loop only examines url, url1, and url2. A raw permission-grant command can carry its target in an origin field, so a command such as {"action":"grant_permissions","origin":"https://evil.example","permissions":["geolocation"]} can be sent while the current page is admitted and the target origin is not. Validate the permission target with the same origin policy before calling session.run.

[RULE] origin-policy-bypass ·

// front. Live, a refused press of a store's basket button counted as
// one, the controls that read as covered after it were taken for a
// dialog it opened, and the step's failure told a rescue to answer it.
if !refused(&reply) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium critique confident

Preserve front state when a refused press can still land

refused treats every NOT_ACTIONABLE response as proof that no input reached the page, but the new comment explicitly documents an exception: a result card's cover can cause the final mouse event to fail in transit after the card's own control was pressed. That response skips front.act, so the flow keeps the pre-action front state and may interpret subsequent controls as covered or route the step to the wrong rescue. Distinguish a pre-input refusal from this partial-action case using response details, or otherwise preserve the front update for the case that can land.

[RULE] stale-state ·


mod live_calendar_tests;
mod live_controls_tests;
mod live_cover_tests;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority critical security confident

Add the declared test module source files

These module declarations have no corresponding live_cover_tests.rs or live_day_label_tests.rs in the repository, so Rust fails module resolution when compiling the test target. Add both source files (or remove the declarations) before merging.


Additional critique observation

priority critical confident

Add the declared test modules before compiling

[RULE] missing-module

Neither live_cover_tests.rs nor live_day_label_tests.rs exists at this commit, so these declarations produce Rust module-not-found errors and break the build for every caller. Add both files to the commit, or remove the declarations until their implementations are present.

[RULE] missing-module-source ·

self.perform("back", Action::Back)
}

fn dismiss_cover(&self, target: &Candidate) -> DesktopResponse {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high security confident

Check refused pages before running every raw command

The new dismiss_cover operation directly invokes press_cover without checking the current page against allowed_origins. Callers can use this operation after navigation or a redirect to act on a refused page, bypassing the policy that observation now enforces.

[RULE] authorization-bypass ·

let command = convert::action(&action, session.options.default_timeout_ms)?;
// The page may have moved on its own since the last call (a redirect,
// a timer): an action is never sent to a refused one.
session.check_if_readable(false).await?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high security likely

Block permission grants in persistent profiles

Checking that the current page is admitted does not prevent a raw permission command from permanently changing a persistent browser profile. A caller can therefore grant location or similar privileges through this escape hatch, and the grant survives beyond the current session. Reject permission-changing commands for persistent profiles, or require an explicit non-persistent profile before allowing them.

[RULE] permission-escalation ·

Comment on lines +261 to +263
workspace.dismiss_cover(&Candidate::default());
workspace.navigate("https://flights.test");
workspace.dismiss_cover(&Candidate::default());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium security confident

Assert every routing operation succeeds

The new test discards the responses from all three operations, so it would still pass if an operation returned an error as long as the recorder observed the call. Assert each response is successful (and add an explicit failure assertion if failure behavior is part of the contract) so the test covers the intended behavior rather than only invocation routing.

Suggested change
workspace.dismiss_cover(&Candidate::default());
workspace.navigate("https://flights.test");
workspace.dismiss_cover(&Candidate::default());
assert!(workspace.dismiss_cover(&Candidate::default()).ok);
assert!(workspace.navigate("https://flights.test").ok);
assert!(workspace.dismiss_cover(&Candidate::default()).ok);

[RULE] unchecked-test-result ·

let id = self
.ensure_session()
.map_err(|error| Box::new(failure("observe", &error)))?;
let checking = self.browser.check_page(&id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium security confident

Hold the session lock through the policy-protected operation

check_page validates the current page while briefly holding the session lock, but the lock is released before see or snapshot runs. A navigation can therefore replace the admitted page with a refused origin between the check and the read. Keep validation and the subsequent page operation under the same session lock, or provide an atomic checked-operation API.

[RULE] authorization-toctou ·

@senamakel
senamakel merged commit cee0f0b into tinyhumansai:main Oct 10, 2026
10 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants