Make RSScript development feel closer to Go's edit-test loop while preserving the full Rust parity/soak gates for slices that need them.
Status: proposed. Created 2026-06-20.
The default developer path should be:
rssdev check
rssdev test
rssdev test jit
rssdev soakWhere:
checkis the fastest correctness pass for ordinary compiler/VM edits;testruns only the small local test set by default;test jitopts into Cranelift/native-JIT dependencies explicitly;soakis slow, Docker/parity-heavy, and used only as a slice-exit gate.
The user-facing rule: fast commands by default, expensive commands by name.
cargo test -p rsscript some_name --features native-jitstill builds/runs everyrsscripttest binary before filtering. Use--libor--test nameinstead.native-jitpulls Cranelift. That is correct, but it must never be in the default edit loop.- The workspace default includes many crates. Bare
cargo testis too broad for day-to-day work. rsscript-runtimepulls network/GPU/async-heavy dependencies (reqwest, Tokio, websocket, Metal, ICU/url stack transitively). VM/JIT/compiler tests should not need all of that for the common path.- Normal tests should be documented as Docker Compose commands directly. That keeps parity explicit and avoids a required wrapper layer.
Add a tiny developer command wrapper, either scripts/rssdev or an xtask crate.
Prefer a script first; it is faster to land and easier to change.
Commands:
rssdev check
rssdev test
rssdev test lib
rssdev test runtime <filter>
rssdev test differential <filter>
rssdev test jit <filter>
rssdev test vm-jit <filter>
rssdev soakImplement these mappings:
rssdev check
cargo check -p rsscript
rssdev test
cargo test -p rsscript --lib
rssdev test runtime <filter>
cargo test -p rsscript --test runtime <filter>
rssdev test differential <filter>
cargo test -p rsscript --test differential <filter>
rssdev test jit <filter>
cargo test -p rsscript --test runtime jit_acceptance --features native-jit
cargo test -p rsscript --test differential <filter> --features native-jit
rssdev test vm-jit <filter>
cargo test -p vm-jit <filter>
rssdev soak
docker compose run --rm dev bash -lc \
'RSSCRIPT_FULL_BACKEND_PARITY=1 RSS_DIFF_PROPTEST_CASES=200 RSS_GENERATIVE_CASES=64 RSS_GENERATIVE_MUTATION_CASES=200 cargo test -p rsscript --test differential'
docker compose run --rm dev cargo test -p rsscript --test soak -- --ignoredAcceptance:
- ordinary contributors can run a useful local gate without knowing Cargo's test target syntax;
native-jitis visible in the command name;- Docker is visible in the command name or docs, never hidden in the fast path.
Document a one-time local setup:
brew install sccache
export RUSTC_WRAPPER=sccacheOptional later:
- evaluate a faster macOS linker (
zld/lld) on this repo with a same-machine before/after; - do not commit linker flags until verified on CI and all developer platforms.
Acceptance:
- cold build unchanged or better;
- branch/worktree rebuilds improve materially;
- no required global setup for CI.
Document explicit Docker Compose commands by cost:
docker compose run --rm dev cargo test -p rsscript
docker compose run --rm dev cargo test -p rsscript --features native-jit --no-run
docker compose run --rm dev cargo test -p rsscript --test soak -- --ignoredKeep optional local shortcuts if scripts depend on them, but document Docker Compose as the daily command.
Acceptance:
- normal Docker Compose test command completes;
- native-JIT compile/test command is explicit;
- soak remains opt-in.
The largest structural win is to stop compiling heavy runtime dependencies for VM/JIT tests that do not need them.
Target split:
rsscript-runtime-core
scalar/list/map/string/json helpers, tensor-free, net-free, gpu-free
rsscript-runtime-net
reqwest, tokio-tungstenite, network/process async helpers
rsscript-runtime-gpu
Metal compute
rsscript-runtime-full
feature aggregator used by release/full parity
Shorter-term alternative: feature-gate rsscript-runtime:
[features]
default = ["core"]
net = ["dep:reqwest", "dep:tokio", "dep:tokio-tungstenite"]
gpu = ["dep:rss-metal-compute"]
full = ["core", "net", "gpu"]Then make rsscript depend on the light feature set for normal tests and only enable
full for backend parity/soak.
Acceptance:
cargo check -p rsscriptno longer compiles network/websocket/GPU crates unless a test asks for them;- file/process/network integration tests explicitly opt into the heavier runtime;
- full soak still uses the full runtime feature set.
Keep autotests = false and the four explicit rsscript integration binaries. Add
more only when there is a real isolation payoff.
Rules:
- unit tests for VM/value/JIT internals go under
--lib; - backend differential cases stay in
--test differential; - slow demos stay ignored in
--test soak; - native-JIT tests that only touch
vm-jitstay incargo test -p vm-jit; - avoid test commands that filter after building every binary.
Acceptance:
- docs show exact target-specific commands for common failures;
- no new unignored soak/runtime-heavy tests enter the default local path.
Track three numbers before and after each slice:
time cargo check -p rsscript
time cargo test -p rsscript --lib
time cargo test -p rsscript --test runtime jit_acceptance
time cargo test -p rsscript --test runtime jit_acceptance --features native-jitOptional cold-cache check:
cargo clean
time cargo check -p rsscriptExit gate:
- each slice must improve at least one common command or materially improve command usability;
- no slice may weaken the soak/parity discipline.
- Add
scripts/rssdevwith target-specific commands. - Update development docs to expose Docker Compose commands directly.
- Update
docs/development/DEVELOPMENT.mdto teach the fast loop first. - Add
sccachesetup docs. - Measure the current baseline commands.
- Feature-gate or split heavy runtime dependencies.
- Re-measure and keep only changes that reduce common command time.
This must be enforced like a performance invariant, not left as advice.
Only these commands are considered the official developer gates:
rssdev check
rssdev test
rssdev test jit
rssdev soakDocs, PR templates, and contributor guidance should point to these commands, not raw
cargo test incantations. Raw Cargo commands are allowed for local debugging, but
they are not the documented path.
Establish machine-specific baseline numbers after Slice A lands, then track deltas. Initial target budgets:
rssdev check <= 10s warm, <= 60s cold
rssdev test <= 20s warm
rssdev test jit <= 60s warm after first native-jit build
rssdev soak no short budget; explicit slow gate
The exact numbers can be adjusted after measuring the repo on the reference machine, but every budget must have an owner and a command.
Add a lightweight CI job named dev-speed-smoke:
time rssdev check
time rssdev testThe job should not fail on raw wall-clock time at first because CI machines are noisy. Instead, it should always print the timing summary and fail only on structural violations:
rssdev testmust not enablenative-jit;rssdev testmust not invoke Docker;rssdev testmust not run--test differentialor--test soak;rssdev checkmust not buildvm-jit, network, websocket, GPU, or DB crates unless a feature explicitly asks for them.
Once the baseline is stable, add a warning threshold:
warn when p50 over 7 days regresses by >20%
block only after a human confirms the regression is real
Any new dependency added to one of these crates requires a build-speed note in the PR:
crates/rsscript
crates/runtime
crates/rss-testgen
crates/vm-jit
The note must answer:
Does this dependency enter `rssdev check`?
Does this dependency enter `rssdev test`?
Can it be behind a feature?
Is it only needed by soak/integration/native adapters?
Default answer should be: heavy dependencies live behind features or in adapter crates.
Every new test must declare its intended gate:
unit/lib -> rssdev test
runtime focused -> rssdev test runtime <filter>
differential -> rssdev test differential <filter>
native JIT -> rssdev test jit <filter> or rssdev test vm-jit <filter>
soak/demo/slow -> rssdev soak, ignored by default
Reject changes that add slow, native-JIT, network, GPU, process, or generative tests to
the default rssdev test path.
Feature names must reveal cost:
native-jit
runtime-net
runtime-gpu
runtime-db
full-runtime
soak
Do not hide expensive features behind default. If a feature pulls Cranelift,
network/websocket, Metal/GPU, database clients, or large generated code, it must be
opt-in and named as expensive in docs.
Add this checklist to PR/review templates:
- [ ] Fast path still uses `rssdev check` / `rssdev test`.
- [ ] No new dependency enters the default path without justification.
- [ ] New tests are placed in the right gate.
- [ ] Native-JIT changes ran `rssdev test jit`.
- [ ] Performance/JIT/value-rep slices ran `rssdev soak`.
- [ ] Timing summary included if build/test surface changed.
When the fast path slows down:
- Run the four measured commands from §7.
- Identify whether the regression is dependency compile, crate rebuild, link time, or test runtime.
- If dependency compile: feature-gate, move to adapter crate, or remove.
- If crate rebuild: split module/crate boundaries or reduce build-script invalidation.
- If link time: narrow test target or evaluate linker/cache changes.
- If test runtime: move the test to the correct gate or reduce fixture size.
- Add a regression note to this plan or the relevant PR.
- Do not weaken the full generative soak.
- Do not hide Docker behind a required wrapper layer.
- Do not enable
native-jitby default. - Do not commit platform-specific linker flags without a measured cross-platform path.
- Do not chase release-build speed before the edit/test loop is fixed.