Skip to content

ci: gate pull requests, and check one rev per git source - #21

Open
pathscale wants to merge 4 commits into
masterfrom
ci/pr-gate
Open

ci: gate pull requests, and check one rev per git source#21
pathscale wants to merge 4 commits into
masterfrom
ci/pr-gate

Conversation

@pathscale

Copy link
Copy Markdown
Owner

chuzz ran nothing on a pull request. release.yml fires on push to master and was the only workflow, so the first build of any change was the macOS release job, after the merge.

What runs

job runner covers
fmt ubicloud-standard-2 cargo fmt --all --check
one-rev ubicloud-standard-2 one revision per git source, from Cargo.lock
control ubicloud-standard-4 clippy + tests for chuzz-control
frontend ubicloud-standard-4 lint, typecheck, vitest
app namespace-profile-agency-tahoe clippy + cargo test --workspace for chuzz-gui

Why the split

chuzz-control is platform-neutral and builds and tests on Linux. chuzz-gui pulls the Blitz engine, a macOS preview runtime, and nothing in either manifest is target-gated (confirmed via cargo metadata), so a Linux runner would build the whole windowing stack and fail for reasons no PR introduced. Making that work is separate portability work. So the cheap gates run on Ubicloud and the app is checked on the same Namespace profile release.yml uses.

The rev check

scripts/check-one-rev-per-git-source.sh is agencyzero's, adapted. The engine is a cascade (ps-anyrender to ps-blitz to tauri-runtime-blitz to chuzz) and repinning fewer than all of it puts two copies of a crate in the graph, surfacing as PaintScene not being satisfied, which reads as a broken engine rather than as two of them. It reads the lockfile, so it needs no toolchain and no network. Currently 39 git-sourced packages across 7 repositories, one rev each.

The layouts CLI guard

The frontend job asserts solid-layouts-library is linked into node_modules/.bin before building. That binary is present only because solid-layouts-oxc is a direct devDependency: bun links the bins of direct dependencies and leaves a transitive one under its own dependent, which is how the release job failed for fourteen releases while bun install reported success. A PR-time check names that cause instead of leaving a command not found in a macOS build log.

Incidental fix

Cargo.lock still recorded 0.1.32 for both members; the version bump in b2779ff never regenerated it. Corrected here so a --locked build cannot trip over it.

Verification

Every step run locally before committing:

  • cargo fmt --all -- --check clean
  • cargo clippy -p chuzz-control --all-targets no warnings
  • cargo test -p chuzz-control 15 passed
  • scripts/check-one-rev-per-git-source.sh from the repo root, passes
  • frontend lint 66 files clean, typecheck clean, test:run 15 passed

The app job is the one I could not fully rehearse: it needs the macOS runner and a cold engine build. Its clippy and test invocations are standard, but it is the step to watch on this PR.

meh added 4 commits August 16, 2026 13:06
chuzz ran nothing on a pull request. release.yml fires on push to master
and was the only workflow, so the first build of any change was the macOS
release job, after the merge. That is how a change reaches live without a
fmt, clippy, typecheck or test having run over it once.

The split follows what is actually portable. chuzz-control is
platform-neutral and builds and tests on Linux. chuzz-gui pulls the Blitz
engine, a macOS preview runtime, and nothing in either manifest is
target-gated, so a Linux runner would build the whole windowing stack and
fail for reasons no PR introduced. Making that work is separate
portability work, so the app is checked on the same Namespace profile the
release job uses and the cheap gates run on ubicloud-standard-*.

scripts/check-one-rev-per-git-source.sh is agencyzero's, adapted. The
engine is a cascade (ps-anyrender, ps-blitz, tauri-runtime-blitz, chuzz)
and repinning fewer than all of it puts two copies of a crate in the
graph, which surfaces as PaintScene not being satisfied and reads as a
broken engine rather than as two of them. It reads Cargo.lock, so it
needs no toolchain and no network.

The frontend job asserts solid-layouts-library is linked into
node_modules/.bin before it builds. That binary is present only because
solid-layouts-oxc is a direct devDependency: bun links the bins of direct
dependencies and leaves a transitive one under its own dependent, which
is how the release job failed for fourteen releases while bun install
reported success. A PR-time check names that cause instead of leaving a
command-not-found in a macOS build log.

Cargo.lock still recorded 0.1.32 for both members; the version bump in
b2779ff never regenerated it. Corrected here so a --locked build cannot
trip over it.

Verified locally: cargo fmt --all --check, cargo clippy -p chuzz-control
--all-targets, cargo test -p chuzz-control (15 passed), the rev check from
the repo root, and the frontend's lint (66 files), typecheck and test:run
(15 passed).
The one guest failure that looks like a success: it instantiates, exports
`run`, returns OK and never touches the document, so the page comes out
blank with nothing to explain it. `run_guest_bytes` already warns on it,
and that warning was untested.

The three cases in `a_failed_module_leaves_the_fallback_standing` do not
reach this path. Each fails before or during the call (a selector matching
nothing, bytes that are not a module, a missing entry export) while this
one gets all the way to Ok, so it needs its own test.

Both halves matter. The first asserts the inert guest builds nothing; the
second runs the fixture guest through the same door and asserts it does
build, so the first cannot pass by `run_guest_bytes` having quietly
stopped running guests at all. Checked by mutation: swapping the inert
module for the fixture fails the first assertion.
`--capture` loaded through `document_loader`, which fetches and parses as
HTML unconditionally, so `view-source:` was the one address a tab could
show and a PNG could not. The scheme is not fetchable, so the branch has
to come before the net provider sees the request: the inner URL is what
gets fetched, and the bytes are escaped rather than parsed.

`browser::source_html` is reused rather than copied. What the capture
writes has to be byte-for-byte what the tab shows, or the PNG stops being
evidence about the browser and becomes evidence about the loader. That
made the function pub(crate), which is the whole of the change to
browser.rs.

A source document has no scripts to run and no images to wait for, so it
returns before the script pump.

This gives the chrome-free PNG plus tree dump the paper wanted: no tab
strip, no toolbar, no menu bar, and regenerable by a reviewer from the
command line rather than from a screen recording.

The test is hermetic. Driving the loader end to end would put a network
round trip in the suite; what can actually regress is the escaping, so it
paints what the loader would hand the renderer and reads the pixels and
the tree back. Checked by mutation: feeding the raw markup instead of the
escaped wrapper fails on an <h1> appearing in the tree.

Verified by hand as well:
  chuzz --capture out.png view-source:https://example.com
writes the escaped source in a <pre>, title "Source", 1440x110.
The binding already worked. `resolveBrowserShortcut` maps Cmd-U to
view-source and `runShortcut` opens the tab, but a keystroke with no menu
entry is undiscoverable: someone who does not already know it has no way
to find it.

The whole bar is built rather than the one submenu, because setting a menu
replaces Tauri's default wholesale. Leaving out the app submenu would take
Quit, Hide and About with it, and leaving out Edit would break Copy and
Paste in the address bar, where those are menu-driven on macOS. Everything
except View is predefined.

The item emits `menu-view-source` and the chrome runs it through the same
`runShortcut("view-source")` the keystroke does, rather than reimplementing
it in Rust. What view source means depends on the active tab, including
refusing to open `view-source:view-source:`, and that is a fact the
frontend has and the menu handler does not.

The id is also the event name, and the two live in different languages
with nothing but a string connecting them. Renaming one leaves an item
that emits into the void: still enabled, does nothing, reports no error.
So a test reads the TypeScript from disk and pins the constant against
`BrowserEvents`, the store's subscription and the mock's handler map, all
three. Checked by mutation: renaming the constant fails with a message
naming the fix.

Verified in the running window over the control socket: Cmd-U on
example.com opens a second tab titled "source of
view-source:https://example.com/".
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant