Integrated browsing: shared browser policy crate, and a Browse surface in AgencyZero - #202
Open
pathscale wants to merge 4 commits into
Open
Integrated browsing: shared browser policy crate, and a Browse surface in AgencyZero#202pathscale wants to merge 4 commits into
pathscale wants to merge 4 commits into
Conversation
added 4 commits
August 31, 2026 20:25
Tabs, back/forward history, address-bar resolution and load outcomes, with no engine dependency: the policy answers "this tab, at this generation, wants this URL" and the host does the fetching. Chuzz already keeps browser policy separate from the renderer — it is the first rule in its working agreement — but the separation is a module boundary inside one binary, so agencyzero cannot reach it. This is the same line drawn at a crate boundary.
Tauri commands over ps-browse-core, a blitz-net fetch per navigation, and a poll hook on the chrome document that attaches the fetched page to its <web-view> mount. The policy decides and the host fetches: a load carries the generation it was issued at, so a page you navigated away from cannot arrive over the one you asked for. The mount is looked up on the UI thread, and a bundle whose mount has not been rendered yet is held rather than dropped — a page that loads and renders nowhere is indistinguishable from one that failed.
A browsing pane beside Home: its own tab strip, address bar, history controls and a debugging drawer, over a <web-view> mount the engine attaches pages to. The expand control sits at the left edge of the title bar, where the window's content begins, so it reads as widening into a larger surface rather than as one more utility tab. The mock implements the surface for real — tabs, history, the same address policy — because the app is verified headlessly against it, and a mock more permissive than the Rust would pass a test the app fails. It reports canRender: false, which is also how the chrome's no-renderer state becomes reachable outside a webview-only build.
The JSX declaration for the page mount moves to a module of its own: a declare module in a script file declares an ambient module that replaces the real one, and in env.d.ts it made every JSX.Element in the app resolve to nothing. The address bar becomes Input.Field. The control contract bans the raw HTML elements outright and requires every value-bearing control to be one the QA suite already drives, so a raw input would have shipped an address bar no rendered test could type into.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
H5: browsing integrated into AgencyZero, built as a shared library rather
than as a viewport, per the owner's direction: "chuzz browser engine should
ideally be a lib design so chuzz and az can share it. AZ will get a dedicated
viewing place kinda like Home tab."
Three commits, in order:
1.
ps-browse-core— browser policy as a crateTabs, back/forward history, address-bar resolution and load outcomes, with
no engine dependency at all (
serdeandurl, that is the whole set).Chuzz already keeps browser policy separate from the renderer — it is the first
rule in its working agreement — but the separation is a module boundary inside
one 1700-line file in one binary, so AgencyZero could not reach it. This is the
same line drawn at a crate boundary.
The shape that makes it shareable is
Load: the policy never fetches. Itanswers "this tab, at this generation, now wants this URL", the host performs
the fetch with whatever net stack it has, and reports back. Nothing mentions a
document, a node or a window, which is why the whole thing is testable without
a compositor — 36 tests, milliseconds.
2. Host wiring in
az-guiapps/gui/src/browse.rs: Tauri commands over the policy, ablitz-netfetchper navigation, and a poll hook on the chrome document that attaches the
fetched page to its
<web-view>mount. A load carries the generation it wasissued at, so a page you navigated away from cannot arrive over the one you
asked for. A bundle whose mount has not been rendered yet is held rather than
dropped: a page that loads and renders nowhere is indistinguishable from one
that failed.
blitz-netandblitz-traitsare added on the same^0.3line asblitz-domand
blitz-script. They have to be — two engine versions in one graph put twoNetProvidertraits in it.3. The Browse surface
A pane beside Home: its own tab strip, address bar, history controls, a
debugging drawer, over the
<web-view>mount. The expand control sits at theleft edge of the title bar, where the window's content begins, so it reads
as widening into a larger surface rather than as one more utility tab.
The mock implements the surface for real — tabs, history, the same address
policy — because this app is verified headlessly against the mock, and a mock
more permissive than the Rust would pass a test the app fails.
What chuzz adoption still needs
apps/chuzz/src/browser.rsstill has its own copy of this policy. Replacing itis mechanical but needs
ps-browse-corepublished first: chuzz takes everydependency as a caret range from crates.io, deliberately, so a path dependency
is not an option there. Nothing in the crate depends on AgencyZero, so that
flip is the only work standing between the two applications and one policy.
publishis left at the workspace default rather than flipped here, becausepublishing a crate is not this PR's call to make.
Verified
cargo test -p ps-browse-core— 36 passedcargo test -p az-gui browse— 4 passedcargo check -p az-gui,cargo clippy,cargo fmt --all— cleanbun run typecheck— cleanbun run lint— clean, including the control-ownership contractbun run test:run— 394 passed, 41 filesNot verified
Nobody has seen this on screen. No
cargo tauri buildhas been run fromthis clone and no window has been opened, so the layout, the mount, and whether
a page actually paints into the
<web-view>are all unconfirmed. This machinehas no screen recording access, so a human has to look. The engine-side risk is
concentrated in one place:
mount_nodeinbrowse.rsand the element id theBrowse pane renders have to agree, and when they drift the page loads correctly
and appears nowhere.
Design (H6) is not in this PR. The Browse pane is a tab kind, so a Design pane
slots in beside it without either owning the other's surface.