Skip to content

feat: per-step screenshot sink + push-gate hardening (4.3.0) - #71

Open
KeyCode17 wants to merge 10 commits into
mainfrom
feat/step-screenshot-sink
Open

feat: per-step screenshot sink + push-gate hardening (4.3.0)#71
KeyCode17 wants to merge 10 commits into
mainfrom
feat/step-screenshot-sink

Conversation

@KeyCode17

Copy link
Copy Markdown
Owner

Summary

Adds an opt-in visual trail of an agent run, and closes gaps found in a baseline-standards audit of the repo.

Screenshots were reachable only through the screenshot action, which returned base64 into an action result that nothing persisted. This adds a StepScreenshotSink port so the host project owns the destination — a database, object storage, anything — while FolderScreenshotSink ships as the batteries-included local-directory default. No storage dependency enters this workspace.

let history = RunAgent::new(task, llm, registry, browser, events)
    .with_screenshot_sink(Arc::new(FolderScreenshotSink::new("./shots")))
    .execute()
    .await?;

Files land at ./shots/<agent-uuid>/step-0000.png, zero-padded so lexicographic order matches run order. StepRecord.screenshot stores the location, not inline bytes, so history JSON stays small; the field is #[serde(default)] so older history still deserializes. Capture or save failure logs at warn and yields no artifact — a full disk never aborts a run.

ras-session carries the sink through SpawnParams.screenshot_sink, so the primitive lands with every consumer migrated in the same PR.

Also in here

Findings from a baseline-standards pass, each its own commit:

  • bump-gate returned success when the version was unchanged, so pushes landed with no bump and the size was never checked. The root workspace version had drifted to 2.7.0 while v4.1.0 was tagged. It now derives the required bump from what the branch adds to origin/main.
  • check-commit-msg accepted chore(scope), docs(scope), an invented release: type, capitalized/period-terminated subjects, and AI attribution trailers.
  • Docs sorted into docs/guides/ and docs/rfcs/; README linked a specs file that never existed.
  • clear_context_cookies removed — no callers, silenced by allow(dead_code).

Debt fixed on the way through

RunStep::new took seven positional arguments and this needed two more, so it moves to a RunStepDeps parameter struct.

Verification

scripts/bump-gate.sh run end to end, not a dry run:

[bump-gate] 4.2.0 -> 4.3.0 (minor)
cargo build --workspace --all-targets    OK
cargo test --workspace --no-fail-fast    OK (38 passed, 0 failed, 2 ignored)
doc-tests, all crates                    OK
cargo run -p ras-cli -- --help           OK
[bump-gate] OK

Plus cargo fmt --all --check, cargo clippy -p ras-agent -p ras-session --all-targets -D warnings, and check-loc.sh / check-no-comments.sh / check-no-unwrap.sh on every changed .rs. Four new tests cover the folder sink: path layout, directory creation, jpeg extension, zero-pad ordering.

  • Live browser run against a real CDP endpoint — the sink is covered by unit tests only; capture itself goes through BrowserPort::screenshot, which is exercised by the #[ignore]d live tests.

Notes for the reviewer

Two rules changed shape during this work and are worth an explicit look:

  1. feat bumps minor, not major. The convention as originally written made every feature a major bump; 4.3.0 for a feature release is only consistent with minor. An explicit ! still forces major.
  2. The bump is sized against origin/main, not the tracking branch. Caught by the real gate after the first push: once a branch is pushed, upstream becomes the branch, so a follow-up bump-only commit measured 2 files and demanded a patch.

lefthook is not installed in the working clone (.git/hooks/ is all .sample), so none of these gates fire automatically there — every check above was run by hand. lefthook install closes that.

Changelog entries for the 3.x line and 4.0.04.2.0 are still missing from CHANGELOG.md; noted in the file rather than left silently absent.

KeyCode17 added 10 commits July 23, 2026 22:02
Runs had no visual record: the only screenshot path was the `screenshot`
action returning base64 into an action result, which nothing persisted.

Adds a `StepScreenshotSink` port so the host project owns the
destination — a database, object storage, or the bundled
`FolderScreenshotSink` writing `{root}/{agent_id}/step-{n:04}.png`.
Capture runs after each step's actions settle, beside the DOM snapshot,
and `StepRecord` carries the returned location rather than inline bytes
so history JSON stays small.

Capture and save failures log and yield `None`; a full disk or a dead
CDP connection degrades the artifact, never the run.

`RunStep::new` took seven positional arguments and this needed two more,
so it moves to a `RunStepDeps` parameter struct.
Sessions build their own `RunAgent`, so the sink has to travel with the
per-session wiring for screenshots to reach a spawned task.
bump-gate returned success when the workspace version was unchanged, so
pushes landed with no bump at all, and it never checked the bump size.
It now derives the required bump from the pushed commits and fails on a
missing, backwards, or wrong-sized change. A root version that had
drifted to 2.7.0 while v4.1.0 was tagged is the failure this closes.

check-commit-msg accepted `chore(scope)`, `docs(scope)`, an invented
`release:` type, capitalized and period-terminated subjects, and AI
attribution trailers. It now rejects each.
architecture and porting notes sat at the docs root, and the phase plans
lived under a superpowers/plans path keyed by date rather than category.
README pointed at a specs file that never existed.
The function had no callers and carried an allow(dead_code) to stay
quiet; BrowserPort::clear_cookies is per-target and backed by
cdp_clear_cookies.
foo is a disallowed placeholder name.
bump-gate compared against the tracking branch, so once a feature branch
was pushed the next push measured only the delta since that push: a
bump-only commit touching Cargo.toml and Cargo.lock demanded a patch
even though the branch shipped a feature. A branch's version describes
what it adds to the release base, so the base is now origin/main and a
feat asks for minor, with an explicit `!` still forcing major.
The hook table claimed bump-gate only fires on a version change and that
commit-msg checked the type alone; both changed when the gates were
tightened.
The file stopped at 2.1.0; the 3.x line and 4.0.0-4.2.0 remain
undocumented and are noted as such rather than left silently absent.
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