Skip to content

feat(cli,core,cdp): --viewport flag + viewport multi-run orchestration - #103

Merged
aram-devdocs merged 4 commits into
mainfrom
codex/16-feat-cli-viewport-flag-multirun
Apr 24, 2026
Merged

feat(cli,core,cdp): --viewport flag + viewport multi-run orchestration#103
aram-devdocs merged 4 commits into
mainfrom
codex/16-feat-cli-viewport-flag-multirun

Conversation

@aram-devdocs

Copy link
Copy Markdown
Owner

Target branch

  • This PR targets main

Spec

Fixes #16. Part of #10 Phase 1, Gate 2, Batch 1B (sibling: #15 DOMSnapshot integration).

PRD references: §10.3 (data flow / per-viewport pipeline), §13.3 (exit codes), §15.4 (plumb lint flags).

Summary

  • Adds repeatable --viewport <name> flag to plumb lint. Filters the configured viewport set from plumb.toml; absent the flag, every configured viewport runs. Unknown names produce a clear input error (exit 2) listing the available viewports.
  • New BrowserDriver::snapshot_all trait method with a default fan-out impl. ChromiumDriver overrides it so Chromium launches exactly once per CLI invocation for the full viewport batch (the per-viewport DOMSnapshot conversion still returns CdpError::NotImplemented until feat(cdp): DOMSnapshot.captureSnapshot integration with style whitelist #15 lands).
  • New plumb_core::run_many aggregates rule output across multiple snapshots, re-sorts by (rule_id, viewport, selector, dom_order), and dedups. The existing exit_code_for then computes worst-severity-wins across all viewports (AC chore(roadmap): link phase-2 parent #4).

Crates touched

  • plumb-core — new run_many entry point; run is now a thin wrapper.
  • plumb-format
  • plumb-cdpBrowserDriver::snapshot_all + viewport-aware FakeDriver.
  • plumb-config
  • plumb-mcp
  • plumb-cli--viewport flag + orchestrator + LintError (thiserror).
  • xtask
  • docs/
  • .agents/ or .claude/
  • .github/

System impact

  • New public API item — plumb_core::run_many, BrowserDriver::snapshot_all. Both have full rustdoc with # Determinism notes; both are infallible-or-Result shaped per the existing patterns.
  • New MCP tool
  • New rule
  • CDP / browser surface change — BrowserDriver::snapshot_all added; security-auditor reviewed.
  • Config schema change
  • Dependency added / bumped — plumb-cli adds thiserror (workspace dep already in tree); tempfile added to [dev-dependencies] only.
  • Determinism invariant touched — run_many re-sorts + dedups across snapshots; tested input-order-independent.

Architectural compliance

  • Layer discipline holds — plumb-core adds no internal deps; plumb-cdp still depends only on plumb-core; only plumb-cli prints.
  • Error shape — LintError is thiserror-derived; anyhow only at the orchestrator boundary.
  • No new unwrap/expect/panic! in libraries. The unreachable empty-pop case in ChromiumDriver::snapshot returns a typed CdpError::Driver rather than panicking.
  • No new SystemTime::now / Instant::now in plumb-core.
  • No new HashMap in observable output paths (IndexMap throughout).
  • No new #[allow(...)] annotations.

Test plan

  • just validate passes locally (54 tests, 0 failed).
  • cargo xtask pre-release (no rule or schema change).
  • just determinism-check — three byte-identical runs.
  • cargo deny check — advisories ok, bans ok, licenses ok, sources ok.
  • New tests added:
    • plumb-core::engine_run_many — 3 cases (collects-from-every, sort order, input-order independence).
    • plumb-cdp::snapshot_all_default::fake_driver_snapshot_all_preserves_target_order_and_viewport — 1 case.
    • plumb-cli::commands::lint::tests — 7 cases on resolve_targets (default fallback, IndexMap order, filter, unknown-name error shape).
    • plumb-cli::tests::cli_integration — 4 new cases covering all four ACs end-to-end.

Documentation

  • Rustdoc on every new public item (run_many, snapshot_all, LintError, the new Lint::viewports flag).
  • # Errors not needed for run_many (infallible) or snapshot_all (already documented CdpError).
  • docs/src/ — no user-facing book changes in this PR. CLI reference docs for --viewport will land alongside the broader CLI docs page in a later PR (humanizer pass deferred to that PR).
  • docs/src/rules/ — no new rules.
  • CHANGELOG — no entry needed; release-please owns it from PR chore(roadmap): link phase-1 parent #3 onward.
  • Humanizer skill — not run (no docs/src/** changes).

Breaking change?

  • No

Checklist

  • Conventional Commits title
  • Branch name: codex/16-feat-cli-viewport-flag-multirun
  • All review gates passed: spec → quality → architecture → test (+ security).

Reviewer notes

  • The ChromiumDriver real path still returns CdpError::NotImplemented per feat(cdp): DOMSnapshot.captureSnapshot integration with style whitelist #15. This PR's job is the orchestrator + single-launch invariant; the per-viewport DOMSnapshot conversion lands in feat(cdp): DOMSnapshot.captureSnapshot integration with style whitelist #15. The two PRs can land in either order — they don't conflict.
  • Config::viewports is empty by default. The default-fallback path (single desktop 1280×800 target) preserves the walking-skeleton quickstart so plumb lint plumb-fake://hello works in a fresh checkout. Once a [viewports.*] section is added to plumb.toml, the bare plumb lint <url> command begins running every configured viewport — that's per PRD §10.3.
  • Empty-config + --viewport <name> arg silently falls back to the default desktop target rather than erroring. This is documented in resolve_targets's rustdoc and asserted by empty_config_ignores_viewport_arg_and_returns_default. Erroring would regress the no-config quickstart.
  • Unknown-viewport input error returns exit 2 ("CLI / infrastructure failure") per the existing crates/plumb-cli/CLAUDE.md mapping. Spec reviewer flagged this as a divergence from PRD §13.3's literal "exit 3 for input errors" but accepted it as consistent with the established CLI convention; if the PRD is canonical, that reconciliation is a separate ticket.

🤖 Generated with Claude Code

aram-devdocs and others added 4 commits April 24, 2026 15:33
New entry point that takes any iterator of snapshots and returns
the deterministic, sorted, deduped union of their violations.
`run` is now a thin wrapper. Sort key is unchanged:
(rule_id, viewport, selector, dom_order).

Refs #16

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New `BrowserDriver::snapshot_all` reuses a single browser session
across multiple targets. ChromiumDriver overrides it to launch
Chromium exactly once per CLI invocation and validate the
version once; per-target snapshot work is still
`CdpError::NotImplemented` until #15 lands. FakeDriver now
carries the requested viewport on the canned snapshot so
downstream multi-viewport orchestrators have distinguishable
per-viewport output.

Refs #16
Adds repeatable `--viewport <name>` flag to `plumb lint`. CLI
resolves the configured viewport set, optionally filtered by the
flag, builds one `Target` per viewport, and calls
`BrowserDriver::snapshot_all` once so Chromium launches exactly
once per CLI invocation. Violations from every viewport flow
through `plumb_core::run_many` and into the existing exit-code
aggregator, so the worst severity across viewports wins.

Unknown viewport names produce a clear input error (exit 2)
listing the configured viewports.

Closes #16

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rustdoc with -Dwarnings rejects public-item docs that link to
private items. The reference is informational; replace the link
with plain prose so `cargo doc --no-deps` stays clean.

Refs #16
@aram-devdocs
aram-devdocs merged commit 0b7ee6e into main Apr 24, 2026
14 checks passed
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.

feat(cli,core): --viewport flag + viewport multi-run orchestration

1 participant