Skip to content

CLI: migrate to clap; add wizen, compose-runner, run subcommands - #86

Merged
lann merged 1 commit into
mainfrom
cli-clap-compose-run-wizen
Aug 11, 2026
Merged

CLI: migrate to clap; add wizen, compose-runner, run subcommands#86
lann merged 1 commit into
mainfrom
cli-clap-compose-run-wizen

Conversation

@lann

@lann lann commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Implements the CLI half of #85 (plus the compose/run items from #13's charter).

What

  • clap 4 migration: lock/fold/aggregate/emit/pins keep their flags, semantics, and verdict exit codes. Usage errors now exit 2 with clap's messages (previously 1 via bail); duplicate scalar flags now error instead of last-wins. Every -o gains a --output long form.
  • wizen (alias wizer): Productize wizer pre-initialization: library entry point, setup action, discoverability #85's subcommand, subsuming the deleted wizer-preinit bin. The mechanism lands as library entry points in component-test-runner — wizen::wizen / wizen::wizen_with (feature wizer), mirroring Runner::new/with_data so SUT-importing suites reuse their existing linker setup (Productize wizer pre-initialization: library entry point, setup action, discoverability #85's library checkbox). Docs carry the required caveats: the snapshot freezes what init observed (env/entropy/clocks); run the wizened artifact everywhere downstream.
  • compose-runner: the examples/compose topology as a library (wac-graph 0.10), one shared provider instance — what wac plug cannot express. Inputs classify by exports: bare suite → embedded reference provider; bundle (tests + test-context + factory) → provider skipped; partial bundles and already-composed inputs rejected by name. Embedded defaults are size-optimized embed-profile builds of runner-cli (118KB) + provider (68KB) committed under crates/component-test-cli/embedded/, overridable via --runner/--provider; just embed-update regenerates.
  • run: compose-runner + execution — a minimal wasmtime embedding equivalent to wasmtime run -W component-model-async -S p3 (WASI p2+p3, Command + run_concurrent, I32Exit downcast, guest exit code; --jsonl sets the wire format). Accepts suites, bundles, or pre-composed components.

Verification

  • just check, just all (full matrix), just test-wasm — all green.
  • New verify-cli path (wired into all, hence CI): compose-runner's output under the wasmtime CLI, run human + JSONL against the existing Path-2 goldens byte-for-byte, and wizen legs (lock --check on the wizened artifact, host-embed golden, compose+run of the wizened artifact) — finding Runner execution-policy guidance #22 stays true through the productized path.
  • Embedded-artifact freshness is gated behaviorally by verify-cli (a byte-compare gate would violate Lockfile artifact-sha256 binding vs non-reproducible suite builds #44).
  • New empirical fact recorded in the commit: a wizened suite composes and runs under wac-graph composition — wizer's "nested components" limit applies to inputs, not outputs.

#85 checkboxes covered

  • Library entry point wizen_with for SUT-importing suites
  • component-test wizen subcommand (subsumes the bin)
  • Cross-refs: ct-runner's cases_per_instance docs, README scope list, sample-suite README "Large suites" section, findings driver line

Not covered here (still open in #85): actions/setup wiring, the runner execution-policy doc, the wasm-opt post-pass spike, the #25 close-out comment.

Follow-ups surfaced in review (non-blocking, happy to file)

  1. compose.rs: explicit rejection for the context-without-factory partial-bundle shape (addressed in this PR).
  2. run.rs: document stdin/argv divergence from wasmtime run (addressed in this PR).
  3. Embedded-artifact drift outside sample-suite-golden-visible behavior is ungated; embed-update reminders are the mitigation.

The composition/execution half of the CLI's charter (#13) plus #85's
wizen productization, in one move because all three need the same
dependency step change (the CLI now embeds wasmtime).

clap 4 derive replaces the hand-rolled parser: lock/fold/aggregate/
emit/pins keep their flags, semantics, and verdict exit codes; usage
errors now exit 2 with clap's messages (previously 1 via bail). pins
keeps its check-vs-bump split (args_conflicts_with_subcommands +
subcommand_negates_reqs); every -o gains a --output long form.

wizen (alias wizer): wizer pre-initialization as a first-class
subcommand (#85). The mechanism moves into component-test-runner as
wizen/wizen_with (feature `wizer`), mirroring Runner::new/with_data so
SUT-importing suites reuse the linker setup they already have —
instantiation is eager, so the shipped driver alone cannot wizen them.
The wizer-preinit bin is subsumed and deleted. The docs carry the
non-negotiable caveats: the snapshot freezes what init observed (env,
entropy, clocks), and the wizened artifact must be used everywhere
downstream.

compose-runner: the examples/compose topology as a library (wac-graph
0.10) — one shared provider instance feeding the suite's test-context
and the runner core's factory/test-context, which is exactly what wac
plug cannot express. Inputs classify by exports: bare suites get the
provider; bundles (tests + test-context + factory re-exported) skip
it; partial bundles and already-composed components are rejected by
name. Defaults are size-optimized `embed`-profile builds of runner-cli
and provider committed under crates/component-test-cli/embedded/
(118KB + 68KB), overridable via --runner/--provider; regenerate with
`just embed-update`. Freshness is gated behaviorally — verify-cli
diffs their output against the Path-2 goldens; a byte-compare gate
would violate #44's no-cross-environment-reproducibility rule.

run: compose-runner + execution in one step. A minimal wasmtime
embedding equivalent to `wasmtime run -W component-model-async -S p3`:
WASI p2 (suite/provider std imports) + p3 (the runner core's stdout
and run entry point), Command::instantiate_async + run_concurrent,
I32Exit downcast, exit code from the guest. Env is explicit like
wasmtime run's; --jsonl sets COMPONENT_TEST_JSONL=1 for the wire
format.

verify-cli joins `just all` (so CI gates it): compose-runner's output
under the wasmtime CLI, run's human + JSONL legs against the existing
Path-2 goldens byte-for-byte, and wizen legs proving finding #22 stays
true through the productized path — the wizened sample suite passes
lock --check, reproduces the host-embed golden, and composes + runs
identically. New wasm-gated integration tests cover the same from
cargo (`just test-wasm`).

Verified: just check, just all (full matrix incl. verify-cli), just
test-wasm; manual legs for bundle input, pre-composed input, wizer
alias, overrides, and rejection messages. Also verified along the way:
a wizened suite composes and runs under wac-graph composition — wizer
output stays a plain component (the "nested components" limit applies
to wizer inputs, not outputs).
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