RSScript development is spec-first and product-contract-driven. The goal is not to accumulate fixtures or backend experiments; it is to keep one small, deterministic compilation and execution path correct and auditable.
-
Implement the real prerequisite first.
If a feature needs syntax, HIR facts, type inference, runtime support, or verifier facts that do not exist yet, build that prerequisite before the feature. Do not encode a one-off lowering shortcut, fixture-only bypass, or runtime fallback that preserves a different language model.
-
Check equals build.
A program
rss checkaccepts must build, verify, and run. A lowering or verification refusal for checked code is a bug in the lowerer or the checker, never a limitation to document.fixture_build_corpusbuilds every pass fixture with amain; its allowlist exists only to record a gap while it is being closed, and it is empty. -
Facts are proofs, and unknown is honest.
Typed executable facts, native region facts, and analysis are derived from MIR and the verifier. Where a fact cannot be proved, publish
Unknown; never publish a guess. The interpreter is the oracle for every other engine: identical outcome, termination reason, and usage counts, or decline. -
Measure generation, do not assume it.
The language exists to be written by models. A change that claims to help generation is measured with the eval corpus (
evals/, the sample collector, andagent-eval) before and after, and the report records the counts. Syntax sugar is admitted only when it desugars to an existing AST node and a measured failure class justifies it. -
Prefer fewer, harder tests.
Tiny fixtures are useful for a specific diagnostic regression. They are not enough to prove the language. Every new semantic rule gets a rejected fixture with its exact code, an accepted fixture, and, where the rule affects execution, an SDK test that builds, verifies, and runs the shape.
-
No aliases or compatibility shims by default.
RSScript is still pre-adoption. Prefer one canonical spelling and migrate all tests, examples, and specs to it. Do not keep legacy aliases unless there is a current external compatibility contract. Did-you-mean tables suggest a real name; they never make an invented one resolve.
-
Keep documents synchronized with the code.
docs/spec/RSScript_Semantics_v0.7.mdstates each rule with its file and diagnostic citation and every fenced example is re-run;docs/generated/is regenerated by xtask, never edited; contract changes carry an ADR. README status sections describe implemented commands only.
- Core language invariants: named arguments,
read/mut/take,local,manage,fresh,retains, resources, handles, structured async, and the check-equals-build rule that ties them to execution. - The generation oracle and its measured pass rate: diagnostics with machine-applicable fixes, signatures and parameter facts at the cursor, and the eval corpus.
- Native tier parity: exact accounting under every armed limit, so the bounded runner can use the JIT.
- Semantic-fact and execution-report quality.
- Provider conformance and isolated-runner boundary hardening.
Use the pinned toolchain and locked dependency graphs. The supported local gate mirrors Core CI:
cargo fmt --all -- --check
cargo clippy --locked --all-targets --all-features -- -D warnings
cargo test --locked
cargo test --locked -p rsscript-sdk --features execution
cargo test --locked -p rsscript-sdk --test fixture_corpus
cargo test --locked -p rsscript-sdk --features execution --test fixture_build_corpus
cargo test --locked -p rsscript-cli --features execution
cargo run --locked -p rsscript-xtask -- validate-ci
cargo run --locked -p rsscript-xtask -- language-card --check
git diff --checkfixture_corpus checks every tests/fixtures/{pass,fail} file against its
// expect: codes; fixture_build_corpus builds and verifies every pass
fixture with a main. Changes that touch diagnostics or generation are also
scored:
cargo run --locked -p rsscript-xtask -- agent-eval --tasks evals/tasks --candidates evals --output /tmp/agent-eval.jsonThe SDK has explicit integration-test targets because autotests = false.
validate-ci checks workflow package, feature, and test references against
Cargo metadata and rejects unregistered top-level SDK test files. A filtered
test is useful only after the containing registered target has proved that the
filter matches real coverage.
Providers and the runner have focused gates:
cargo test --locked -p rsscript-provider-api
cargo test --locked -p rsscript-provider-conformance
cargo test --locked -p rsscript-provider-fs
cargo test --locked -p rsscript-provider-env
cargo test --locked -p rsscript-provider-process
cargo test --locked -p rsscript-provider-http
cargo test --locked -p rsscript-runner-protocolRust AOT, REIR, and self-hosting research are archived on the
archive/experiments-2026-09 branch and are not built or tested from this
workspace.
Native JIT is an explicit trusted-host SDK mode. It is absent from default closures and requires both correctness and performance evidence:
cargo test --locked -p rsscript-sdk --features native-jit
cargo test --locked --release -p rsscript-sdk --features native-jit --test native_jit_smoke native_hot_loop_release_gate_beats_the_interpreter -- --nocaptureFuzz targets are maintained in their own manifest:
cargo check --locked --manifest-path fuzz/Cargo.toml --binsAvoid concurrent workspace Cargo commands because their build lock makes the feedback slower. Use a focused test during diagnosis, then return to the broad gate. Long-running or platform-specific hardening belongs in its dedicated workflow, not in an invented hidden SDK target.
A single focused test is useful only after a broad command has identified the failure or while editing a narrow regression. Starting every change with a single test costs extra tokens and time because it still needs a full test pass later. The default flow should be:
broad quiet test -> inspect failure -> focused loop -> broad quiet test -> full gate
This keeps the evidence strong while avoiding repeated command output.
A single Docker toolchain image builds and tests the workspace identically on
macOS, Windows, and Linux. It carries the Rust toolchain, cargo-nextest, and
the C build dependencies; the checkout is bind-mounted at /work, so host edits
take effect immediately. Only Docker with Compose v2 is required locally.
docker compose build # first run downloads the toolchain
docker compose run --rm dev cargo test --workspace # the broad gate
docker compose run --rm dev cargo run -p rsscript-cli --bin rss --features execution -- check examples/scripts/basic/hello.rss
docker compose run --rm dev bash # interactive shellEvery command in the testing loop above works unchanged inside the container.
target, the Cargo registry, and Cargo git checkouts live in named volumes so
compilation persists between runs; docker compose down -v resets them. The
image tracks rust:1-bookworm; pin a concrete tag in Dockerfile for a fully
reproducible toolchain. .devcontainer/devcontainer.json reuses the same
service for VS Code and Codespaces, and the image builds natively on amd64
and arm64.