Skip to content
This repository was archived by the owner on Jul 22, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
124 commits
Select commit Hold shift + click to select a range
b16fa17
feat(executor): rework runner ids (contract/chain/custom) ✨
kp2pml30 Jun 19, 2026
cedfce3
chore(build): switch runners to dev mode (hashes=test) 🚧
kp2pml30 Jun 19, 2026
49b40ba
feat(executor): add register_runner gl_call for custom runners ✨
kp2pml30 Jun 19, 2026
2ba2823
feat(wasi): per-permission sandbox allow flags (write/send/register) ✨
kp2pml30 Jun 19, 2026
4c048cd
test(executor): cover malformed and missing custom runner ids ✅
kp2pml30 Jun 19, 2026
4691daa
chore(claude): add branch-review agents and skill 🤖
kp2pml30 Jun 19, 2026
de276c2
feat(wasi): add MapFile gl_call to map runner files at runtime ✨
kp2pml30 Jun 19, 2026
e68cee0
fix(executor): charge custom runner memory once per registration 🐛♻️
kp2pml30 Jun 19, 2026
ae0e998
docs(build): document ya-test-runner --ignore-hash in test skill 📝
kp2pml30 Jun 19, 2026
cc8f8ee
fix(wasi): require read_storage permission for MapFile gl_call 🔒️
kp2pml30 Jun 19, 2026
5033d23
test(executor): unit-test parse_runner_id + document runner id forms ✅
kp2pml30 Jun 19, 2026
9537a04
fix(executor): make register_runners opt-in (drop u from default perm…
kp2pml30 Jun 20, 2026
3595f88
fix(executor): report dev major/minor for vTEST version 🐛
kp2pml30 Jun 20, 2026
e3b418f
chore(build): version-check genvm-common; derive vTEST version from C…
kp2pml30 Jun 20, 2026
74f32c2
refactor(executor): make version::CURRENT a const ♻️
kp2pml30 Jun 20, 2026
bcfb933
feat(executor): add configurable code_slot to contract root slot ✨
kp2pml30 Jun 20, 2026
d875408
feat(executor): verify contract major matches node version ✨
kp2pml30 Jun 20, 2026
016fd38
test(executor): cover major_mismatch reject and code_slot redirect ✅
kp2pml30 Jun 20, 2026
5670e07
fix(codegen): emit From<VmError> for String instead of Into 🐛
kp2pml30 Jun 20, 2026
73f58f2
docs(spec): document root code_slot field and MapFile gl_call 📝
kp2pml30 Jun 20, 2026
d360f41
test(executor): cover map_file refused without read_storage ✅
kp2pml30 Jun 20, 2026
a100a6c
docs(spec): reserved root offsets must stay zero for forward-compat 📝
kp2pml30 Jun 20, 2026
7920346
docs(spec): correct code_slot byte span (5-36) and cache-key note 📝
kp2pml30 Jun 20, 2026
c9d2f0d
test(executor): exec redirected code via code_slot (fails if ignored) ✅
kp2pml30 Jun 20, 2026
cfd150b
test(executor): map_file(contract) uses preloaded archive after code …
kp2pml30 Jun 20, 2026
1d00179
refactor(wasi): move MapFile runner resolution out of vfs into action…
kp2pml30 Jun 20, 2026
4f3ac4c
chore(claude): reviewer-implementation enforces responsibility encaps…
kp2pml30 Jun 20, 2026
87176ba
refactor(wasi): add vfs::Fd newtype and FileContents::from(Bytes) hel…
kp2pml30 Jun 22, 2026
d5be0de
refactor(runners): add Slot.cast and route cast_slot through it ♻️
kp2pml30 Jun 22, 2026
01b43c3
refactor(ci): polish release-notes generator (argparse, cleaner outpu…
kp2pml30 Jun 22, 2026
80deb01
refactor(executor): resolve `contract` runner to its chain id via cod…
kp2pml30 Jun 22, 2026
8c70d9f
refactor(executor): add RunnerId::canonical_id, inline chain_canonica…
kp2pml30 Jun 22, 2026
dce3519
feat(executor): add gvm32 Crockford Base32 codec (rust/python/nix) + …
kp2pml30 Jun 22, 2026
6ce3f2f
feat(executor): encode built-in/custom runner hashes and slot ids wit…
kp2pml30 Jun 22, 2026
e30b027
feat(calldata): add Address::checksum_hex (EIP-55) ✨
kp2pml30 Jun 22, 2026
0e9f528
docs(claude): rust-test-style — public-API tests belong in tests/ 📝
kp2pml30 Jun 22, 2026
4659283
feat(calldata): checksum_hex returns [u8;40]; canonical runner id use…
kp2pml30 Jun 22, 2026
33157e2
refactor(calldata): add checksum_hex_string (String) alongside checks…
kp2pml30 Jun 22, 2026
4ebc3d8
feat(common): add Bytes32Hash type with gvm32 formatting ✨
kp2pml30 Jun 22, 2026
e510fe8
refactor(executor): use Bytes32Hash for custom runner hashes ♻️
kp2pml30 Jun 22, 2026
1971899
refactor(runners): builtin/custom runner hash is Bytes32Hash; dev "te…
kp2pml30 Jun 22, 2026
0a87624
fix(security): obvious fixes from octane analysis 3 🔒
kp2pml30 Jun 22, 2026
6194acd
feat(webdriver): SSRF guard via CDP request interception 🔒
kp2pml30 Jun 22, 2026
74dbb06
feat(webdriver): configurable Chrome launch via env vars 🔧
kp2pml30 Jun 22, 2026
51e675b
docs(spec): random_get fails with errno::io on RNG failure in non-det…
kp2pml30 Jun 22, 2026
12c3e14
fix(webdriver): prevent overlapping browser rotations 🔒
kp2pml30 Jun 22, 2026
920453e
fix(web): reject HTTPS->HTTP downgrade redirects 🔒
kp2pml30 Jun 22, 2026
a6e946a
fix(web): bind @scheme in request signatures 🔒
kp2pml30 Jun 22, 2026
7e50f05
fix(web): normalize headers on unsigned requests too 🔒
kp2pml30 Jun 22, 2026
f647a4f
fix(install): safe executor tar extraction + optional integrity check 🔒
kp2pml30 Jun 22, 2026
0a3a94b
fix(web): bound signer preflight with a default timeout 🔒
kp2pml30 Jun 22, 2026
7226d24
fix(llm): bound provider response body size to cap OOM DoS 🔒️🐛
kp2pml30 Jun 22, 2026
bee9658
chore(install): simplify post-install to interpreter-only patching ♻️
kp2pml30 Jun 22, 2026
15698af
chore(abi): always encode user errors as tagged calldata ♻️
kp2pml30 Jun 22, 2026
e8913cf
chore(abi): make json llm output format behave like json2 ♻️
kp2pml30 Jun 22, 2026
05c1590
chore(abi): remove deprecated Rollback gl_call message variant 🔥
kp2pml30 Jun 22, 2026
9f361b1
fix(executor): reject '..' components when mapping archive files 🔒️
kp2pml30 Jun 23, 2026
52e201b
fix(executor): require 0x prefix on chain runner addresses 🔒️
kp2pml30 Jun 23, 2026
e07012c
fix(common): fail-fast on malformed version strings 🐛
kp2pml30 Jun 23, 2026
6e023f4
docs(sdk): gvm32 encode emits lowercase, not uppercase 📝
kp2pml30 Jun 23, 2026
1bde44c
fix(llm): hard-cap derived response body limit 🔒️
kp2pml30 Jun 23, 2026
38c52fd
fix(install): fail closed on missing executor integrity hash 🔒️
kp2pml30 Jun 23, 2026
5a8c14e
docs(py-std): gvm32 encode emits lowercase, not uppercase 📝
kp2pml30 Jun 23, 2026
b44a79a
fix(nix): validate hex length and runner uid format 🔒️
kp2pml30 Jun 23, 2026
db54fd5
feat(executor): CallContract child is static — forbid events and mess…
kp2pml30 Jun 23, 2026
8cb5a76
docs(spec): CallContract preserves sender_address; immediate caller i…
kp2pml30 Jun 23, 2026
013027c
docs(impl-spec): document executor has no timeout, killed by manager 📝
kp2pml30 Jun 23, 2026
7b4134b
chore(executor): remove graceful-shutdown signal/cancellation dead co…
kp2pml30 Jun 23, 2026
c87be55
docs(spec): RunNondet disables register_runners; link permission spec…
kp2pml30 Jun 23, 2026
8caba68
feat(executor): assert discarded CallContract accumulator is empty 🔒️
kp2pml30 Jun 23, 2026
eceeb7a
docs(spec): CallContract reads committed state, not in-tx delta + tes…
kp2pml30 Jun 23, 2026
26404c9
test(intercontract): drop committed execution hashes (run with --igno…
kp2pml30 Jun 23, 2026
3fc17fc
fix(executor): write contract major on deploy alongside code 🐛
kp2pml30 Jun 23, 2026
9d415ee
test(intercontract): self-CallContract (incl. in deploy) is allowed —…
kp2pml30 Jun 23, 2026
8f401a7
perf(wasi): skip trace message timing/logging when not in debug mode ⚡
kp2pml30 Jun 23, 2026
de9d69a
test(intercontract): self-CallContract in __init__ (deploy) is allowe…
kp2pml30 Jun 23, 2026
a67ab6a
test(intercontract): simplify call_view_committed literals 🎨
kp2pml30 Jun 23, 2026
d4bc56d
fix(manager): bound per-execution log sink unless debug mode 🔒️
kp2pml30 Jun 23, 2026
1731c71
feat(executor): configurable debug_mode with Capture, replacing captu…
kp2pml30 Jun 23, 2026
995b807
docs(impl-spec): document debug_mode levels + Capture; drop capture_o…
kp2pml30 Jun 23, 2026
f97f120
docs(spec): fix RuntimeMicroSec det-mode override + stale debug level…
kp2pml30 Jun 23, 2026
d2b7349
fix(manager): empty genvm_log under disabled capture; test keep_tail ✅
kp2pml30 Jun 23, 2026
77b0cbc
test(runners): custom runner registered in det leaks into nondet scope ✅
kp2pml30 Jun 23, 2026
6b43857
fix(executor): scope custom runners per-execution; don't intern unval…
kp2pml30 Jun 23, 2026
27dc6c7
fix(executor): keep runner.json Depends/With ids as String until vali…
kp2pml30 Jun 23, 2026
c2136c1
fix(scripting): set per-state package.path/cpath instead of process-g…
kp2pml30 Jun 23, 2026
1b87cd6
fix(executor): validate method_hosts indices up front to avoid panic 🔒️
kp2pml30 Jun 23, 2026
de1b7d3
fix(manager): cap max_execution_minutes at 24h (avoid i64 overflow) 🐛
kp2pml30 Jun 23, 2026
f3481b7
refactor(modules): drop get_stats RPC; manager collects metrics direc…
kp2pml30 Jun 23, 2026
965f2fa
fix(scripting): check out lua VMs exclusively from the pool 🔒️🐛
kp2pml30 Jun 23, 2026
fa35b6d
fix(manager): gate version patch-walk by available_after 🔒️🐛
kp2pml30 Jun 23, 2026
e20389b
fix(llm): saturate provider-reported token counts instead of wrapping…
kp2pml30 Jun 23, 2026
bbaa87a
fix(webdriver): isolate each render in its own browser context 🔒️
kp2pml30 Jun 23, 2026
fd4ee9f
fix(executor): reject misleading wss:// module scheme 🔒️
kp2pml30 Jun 23, 2026
c3338a6
chore(abi): remove json2 output format alias 🔥
kp2pml30 Jun 23, 2026
e3100c4
docs: remove rollback terminology, fix user error encoding docs 📝
kp2pml30 Jun 23, 2026
4460c81
docs: remove orphaned doc/internal/node.md 🔥
kp2pml30 Jun 23, 2026
eb7bcf7
chore(abi): remove 4-byte tagged calldata prefix from user error enco…
kp2pml30 Jun 23, 2026
67fa3b4
feat(fees): generalize bucket_no to accept int or array of ints ✨
kp2pml30 Jun 23, 2026
54fb848
fix(webdriver): harden SSRF guard against popups and missing IP range…
kp2pml30 Jun 23, 2026
71d5620
docs: add missing gl.vm migration notes to v0.3 changelog 📝
kp2pml30 Jun 23, 2026
0857d33
chore(abi): move major to root slot offset 0 🔥
kp2pml30 Jun 23, 2026
43f0b9f
feat(runners): optional slot/state in chain runner id, major version …
kp2pml30 Jun 23, 2026
250c234
fix(executor): stricter version string validation in current_version 🔒️
kp2pml30 Jun 23, 2026
bbf7fc1
fix(tests): use print(e) in register_no_perm test 🐛
kp2pml30 Jun 23, 2026
4feba85
chore(tests): fix tests ✅
kp2pml30 Jun 24, 2026
09e9201
feat(sdk): add Yield and GetTimestamp gl_call methods ✨
kp2pml30 Jun 24, 2026
7731c1c
fix(abi): sync codegen root_offsets input with major-first layout 🐛
kp2pml30 Jun 24, 2026
42befce
docs(spec): user_error sub-VM result is calldata, not Rollback string 📝
kp2pml30 Jun 24, 2026
e60de70
docs(spec): drop deprecated Rollback gl_call message 📝🔥
kp2pml30 Jun 24, 2026
1850ea7
docs(fees): document bucket_no array form and atomic debits 📝
kp2pml30 Jun 24, 2026
248d89a
fix(schema): forbid reserved prefixes in runner-id name:hash branch 🔒️
kp2pml30 Jun 24, 2026
e9e8df4
docs(adr): bring runner-id ADR up to date with shipped chain form 📝
kp2pml30 Jun 24, 2026
17d84be
fix(schema): allow optional state/slot in chain runner id 🐛
kp2pml30 Jun 24, 2026
635624b
fix(runners): hide uncommitted deploy code from on-chain runner reads 🔒️
kp2pml30 Jun 24, 2026
1c4ff13
refactor(runners): thread the resolved runner id through the VM confi…
kp2pml30 Jun 24, 2026
1891683
feat(runners): let spawn_sandbox run an explicit runner id ✨
kp2pml30 Jun 24, 2026
5b04cad
test(balances): exercise the self-view after deploy, not in __init__ ✅
kp2pml30 Jun 24, 2026
5761659
test(runners): split major-mismatch into per-entry-point checks ✅
kp2pml30 Jun 24, 2026
4bb5387
test(runners): merge major-mismatch checks into one jsonnet ✅
kp2pml30 Jun 24, 2026
2bf18cc
fix(vfs): release limiter budget when fd allocation fails 🐛
kp2pml30 Jun 24, 2026
2358009
perf(runners): restore binary_search in has_in_all ⚡
kp2pml30 Jun 24, 2026
f5f099f
test(runners): cover register_runner in nondet and runtime map into /…
kp2pml30 Jun 24, 2026
bb04dc5
chore(tests): fix tests ✅
kp2pml30 Jun 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
76 changes: 76 additions & 0 deletions .claude/agents/reviewer-implementation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
name: reviewer-implementation
description: Reviews the implementation of a GenVM branch — code-vs-spec drift, code quality, AI slop, duplicated logic, useless comments, and doc completeness. Use as the "implementation" pass of a branch review.
tools: Bash, Read, Grep, Glob
model: opus
---

You are the **implementation** pass of a GenVM branch review. You read the code
and judge how it is built. Read-only: never edit code.

## Baseline

Diff against the active dev branch, not `main`:

- Default to `v0.3-dev` (or the current `v0.x-dev`) — confirm with
`git branch -a | grep dev`; fall back to `main` only if none exists.
- State the base in one line; ignore commits already on it.
- `git log --oneline <base>..HEAD` / `git diff --stat <base>..HEAD`, then read the
diffs of the changed code.

## What to report (with file:line evidence)

1. **Code-vs-spec drift.** Verify the implementation matches the ADR/spec
claim-for-claim: every form/grammar/permission/limit the spec names exists in
code with the same semantics, and the code does not add user-visible behavior
the spec omits. Call out each divergence.

2. **Doc / SDK completeness.** New `gl_call`s, permissions, runner-id forms, etc.
must be reflected in `doc/website/src/spec/**`, `doc/schemas/*.json`, and any
SDK wrappers/docstrings. Flag anything implemented but undocumented.

3. **AI slop & duplicated logic.** Deliberate engineering or generated filler?
Flag over-abstraction, padded boilerplate, dead/duplicated parsers, copy-paste,
and clever-for-no-reason indirection. Say plainly when it is NOT slop.
Specifically: a new `gl_call` handler (e.g. `register_runner` in
`wasi/genlayer_sdk.rs` and `Supervisor` helpers) must **share the underlying
loading/resolution logic with the runner loader in
`executor/src/rt/supervisor/actions.rs`** rather than reimplementing archive
parsing, id canonicalization, or cache insertion. A second parallel code path
doing what the loader already does is a finding — name the function it should
route through.

**Responsibilities must be encapsulated in the layer that owns them.** Each
layer does its own job and exposes ONE entry point; callers in other layers
delegate, they don't reach across and re-orchestrate. Concretely: the
wasi/vfs layer (`wasi/genlayer_sdk.rs`, `wasi/preview1.rs`) is a thin syscall
shim — it must NOT contain runner-resolution logic (computing a contract's
runner id, picking storage slots/state, stitching together
`get_runner_of_contract` + `load_runner` + archive mapping). That belongs in
the runners/supervisor layer; the gl_call handler should call a single
encapsulated function there. A handler that assembles a cross-layer flow
inline (even if each piece is "shared") is a finding — name the boundary it
violates and the single function it should call instead. Likewise, storage
layout, permission derivation, and limiter accounting each have one home;
flag logic that leaks into a layer that shouldn't know about it.

4. **Correctness & quality.** Panics on malformed input (`slice`, `unwrap`),
error handling, idempotency.

5. **Edge cases are tested.** Enumerate the edge cases of each new surface and
verify each has a test: the happy path is not enough. Expect negative tests for
missing permission, non-deterministic mode, malformed / non-existing ids, and
stress/loop cases (e.g. registering the same thing ~1000× to prove
consume-once). Name each untested edge case as a gap.

6. **Useless comments.** Flag narrate-the-obvious comments. Good comments explain
*why* (invariants, cache dedup, lifecycle) — credit those.

Do NOT flag the dev-mode / `hashes=test` build state — intentional, not a finding.
Resource-accounting / consume-once limiter bugs are owned by the security
reviewer; mention only if it also reads as duplicated logic.

## Style

Concise and direct. Lead with: is the implementation correct and clean enough to
merge? Separate blocking issues from nits. Note if you did not build or run tests.
57 changes: 57 additions & 0 deletions .claude/agents/reviewer-security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
name: reviewer-security
description: Security review of a GenVM branch — attacker mindset over permissions, resource limits, sandbox propagation, parsing, and state-exfiltration. Use as the "security" pass of a branch review.
tools: Bash, Read, Grep, Glob
model: opus
---

You are the **security** pass of a GenVM branch review. Think like an attacker
writing a malicious contract. Read-only: never edit code.

First read the repo root `SECURITY.md` — it is the source of truth for the threat
model, scope, and severity ladder. Rank every finding by the priority it defines
and cite that priority. Do not restate its contents in your report; reference it.

## Baseline

Diff against the active dev branch, not `main`:

- Default to `v0.3-dev` (or the current `v0.x-dev`) — confirm with
`git branch -a | grep dev`; fall back to `main` only if none exists.
- State the base in one line; ignore commits already on it.
- `git log --oneline <base>..HEAD` / `git diff --stat <base>..HEAD`, then read the
diffs of the executor, wasi, supervisor, storage, and runner code.

## What to check (with file:line evidence)

- **Permission gates.** Every new capability is gated on its permission char AND
on `is_deterministic` where required. Check the gate is at entry, before any
side effect.
- **Permission propagation.** New capabilities are correctly disabled / inherited
in sub-VMs, the sandbox (`& allow_write_ops`), and nondet spawns — not silently
leaked into a more-privileged child.
- **Allocation bounded before allocating.** Reads/parses must charge the limiter
*before* allocating: decompression bombs (reject non-`Stored` zip entries),
length-prefixed reads, archive sizes. Charging after the alloc is a finding.
- **Resource accounting is consume-once.** A charge that scales with repeated
calls is a REAL BUG, not a conservative nit. Content-addressed resources (e.g. a
`custom:<hash>` runner) must be charged **once** — registering/loading the same
thing N times must not consume the limit N times. The test: "do it ~1000× in a
loop — does the limit overflow?" If yes, flag it and prescribe dedup-by-hash /
consume-once. Never excuse N-times charging as "errs safe."
- **Strict input parsing.** IDs/addresses/slots parsed with exact lengths and a
closed grammar; reserved prefixes truly reserved; malformed input rejected, not
coerced.
- **Read-oracle / exfiltration.** Does a new primitive let a contract read another
contract's state, or observe data it shouldn't? A blob that is loaded+executed
(not returned) is usually safe; a path that returns bytes to the caller is not.
- **Determinism.** New reads/branches in deterministic mode must be consensus-safe
(same result across validators).

Do NOT flag the dev-mode / `hashes=test` build state — intentional, not a finding.

## Style

Concise. Lead with: any exploitable issue, yes/no, and what blocks merge.
Distinguish a real vuln from a hardening nice-to-have. Note if you did not build
or run anything.
63 changes: 63 additions & 0 deletions .claude/agents/reviewer-spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
name: reviewer-spec
description: Reviews the ADR/proposal and spec/schema of a GenVM branch as documents — soundness, clarity, and completeness (what was forgotten). Use as the "spec" pass of a branch review.
tools: Bash, Read, Grep, Glob
model: opus
---

You review the **specification** of a GenVM branch — the ADR, the spec/docs, the
schemas — as documents: is the proposal sound, clear, and self-consistent? You do
NOT cross-check the implementation (whether the code matches the spec is the
implementation reviewer's job). Read-only: never edit code.

## Baseline

Diff against the active dev branch, not `main`:

- Default to `v0.3-dev` (or the current `v0.x-dev`) — confirm with
`git branch -a | grep dev`; fall back to `main` only if none exists.
- State the base in one line at the top; ignore commits already on it.
- `git log --oneline <base>..HEAD` and `git diff --stat <base>..HEAD`, then read
the diffs of `doc/**` and `*.json` schemas.

## What to report

With file:line evidence:

1. **ADR / proposal quality.** If the branch adds or changes a `doc/adr/*.md`
(or design doc), rate it. Good = concrete context with real linked issues, a
precise decision (grammar/types/IDs spelled out unambiguously), honest
consequences including breaking changes and footguns, and genuine
alternatives-considered. If there's no ADR for a change that warrants one,
say so.

2. **Spec / schema soundness.** Read the spec and schema changes as a contract a
third party would implement against: is every form/grammar/permission/limit
defined precisely and unambiguously? Are there gaps, contradictions, or
under-specified edges? Is the JSON schema itself valid and matching the prose?
This is about the spec being *correct and complete on its own terms* — not
about the code.

3. **Completeness — what did we forget to add?** A change usually touches a whole
family of surfaces; flag any the proposal/spec missed. E.g. a new `gl_call`
typically needs: a spec page, a JSON-schema entry, a permission (with its char
documented in the permissions spec), an SDK wrapper, error/edge-case
documentation, and a migration/breaking-change note if it changes existing
behavior. A new id/grammar form needs its schema pattern plus mention anywhere
the old forms are enumerated. List the surfaces that *should* have changed
together but didn't.

4. **Edge cases are documented or inferrable.** Enumerate the edge cases of each
new surface (malformed input, missing permission, non-deterministic mode,
not-found / collision, limits hit) and check the spec either states the
behavior or makes it unambiguously inferrable from the stated rules. A behavior
a reader would have to guess is a spec gap — list each one. (Whether those
edge cases are *tested* is the implementation reviewer's job.)

Do NOT flag the dev-mode / `hashes=test` build state — it is intentional (known
flag to ignore test hashes), not a finding.

## Style

Concise and direct. Lead with: is the proposal sound and the spec implementable
as written? Separate blocking gaps from nits. Don't pad.
42 changes: 42 additions & 0 deletions .claude/skills/branch-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
name: branch-review
description: Reviews the current GenVM branch by fanning out three specialized review agents (spec, security, implementation). Use when asked to "review this branch", "review the PR", or do a full code review of a diff.
---

# Reviewing a GenVM branch

Run a three-pass review using the dedicated subagents. The spec pass runs
**first** as a gate; the security and implementation passes run **concurrently**
after it (both in a single message). All three are read-only.

| Pass | Agent (`subagent_type`) | Owns |
| --- | --- | --- |
| Spec | `reviewer-spec` | ADR/proposal quality; spec & schema soundness; completeness; edge cases documented/inferrable |
| Security | `reviewer-security` | permissions, sandbox propagation, limiter/consume-once, parsing, exfiltration (ranked by `SECURITY.md`) |
| Implementation | `reviewer-implementation` | code-vs-spec drift, AI slop, duplicated logic, edge cases tested, doc completeness, useless comments |

## Baseline

All three diff against the active **dev** branch, not `main` (default
`v0.3-dev`; confirm with `git branch -a | grep dev`). Pass the base in the prompt
if the user named one. Do NOT treat the dev-mode / `hashes=test` build state as a
finding — it is intentional.

## Procedure

1. Confirm the base branch (default `v0.3-dev`).
2. Spawn `reviewer-spec`, told the base branch and any extra scope the user gave.
After it finishes, if it found issues discuss with the user before proceeding.
3. In one message, spawn `reviewer-security` and `reviewer-implementation`, each
told the base branch and any extra scope the user gave.
4. Synthesize their three reports into one review: lead with the merge verdict,
then a **Blocking** section and a **Nits** section, attributing findings to
their pass. De-duplicate overlaps (e.g. a duplicated-logic issue both security
and implementation raise) into a single entry.

## Scope notes

- If the user asks for only one dimension ("just the security review"), run that
one agent instead of all three.
- Each agent is read-only; none will edit code. If the user wants fixes after the
review, that is a separate, explicit follow-up.
19 changes: 16 additions & 3 deletions .claude/skills/rust-test-style/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,29 @@ To run these tests, see the `/test` skill (`--filter-tag rust`).

## Where tests go

**Decision rule — default to a separate file.** If the item under test is
reachable from the crate's public API (a `pub fn`/`pub` type, even via a
re-export), its test goes in its own `tests/<concern>.rs` file. Use an inline
`#[cfg(test)] mod tests` **only** when the test must reach a *private* item that
cannot be exercised through the public API. A public function tested inline is a
review finding — move it to `tests/`.

Two locations, both in use:

1. **Integration tests** — one file per concern under the crate's `tests/` dir.
Preferred for exercising a crate's public API. Each `tests/*.rs` file is its
own compilation unit and gets its own runner case.
**This is the default** for anything testable through the public API. Each
`tests/*.rs` file is its own compilation unit (a separate crate) and gets its
own runner case.
- e.g. `executor/crates/calldata/tests/derive_decode.rs`,
`executor/crates/calldata/tests/address_checksum.rs`,
`executor/crates/common/tests/expr.rs`,
`modules/implementation/tests/test_rat.rs`
- Because each is a separate crate, it sees only the library crate plus
`[dev-dependencies]` — **not** the library's regular `[dependencies]`. If a
test needs a util the crate already depends on (e.g. `hex`), add it to
`[dev-dependencies]` too.
2. **Inline unit tests** — `#[cfg(test)] mod tests { ... }` at the bottom of a
`src/*.rs` file, for testing private items. e.g.
`src/*.rs` file, reserved for testing **private** items. e.g.
`executor/crates/calldata/src/lib.rs`, `executor/crates/common/src/logger/mod.rs`.

```rust
Expand Down
7 changes: 7 additions & 0 deletions .claude/skills/test/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ ya-test-runner run [OPTIONS]
| `--fail-fast` | Stop execution after first failure |
| `--coverage` | Enable coverage collection for Rust tests |
| `--log-level LEVEL` | Set log level (trace/debug/info/warning/error) |
| `--ignore-hash` | Skip `.hash` (execution-hash) comparison entirely |

**`--ignore-hash`:** integration cases compare both the printed semantics
(`.N.stdout`) and a deterministic execution hash (`.N.hash`). When adding a new
case, you usually don't have a correct `.hash` yet — run with `--ignore-hash` so
only the `.stdout` semantics are checked, or set `stable_hash: false` on the
entry (then validators compare to the leader's hash instead of a committed file).

### Show Information
```bash
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,4 @@ repos:
entry: ./support/ci/check-versions.py
language: system
pass_filenames: false
files: ^(executor/Cargo\.toml|modules/implementation/Cargo\.toml|\.genvm-monorepo-root)$
files: ^(executor/Cargo\.toml|executor/crates/common/Cargo\.toml|modules/implementation/Cargo\.toml|\.genvm-monorepo-root)$
8 changes: 6 additions & 2 deletions configure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -483,14 +483,18 @@ def generator.register_cargo(rel_path, extra_args: [], build_to: nil)
var :pool, :console
end

runners_nix_inputs = $source_dir.join('runners').glob('**/*.nix')

generator.build(:nix_eval, 'out/executor/vTEST/data/latest.json') do
var 'expr', 'let drv = import ./runners { host-system = builtins.currentSystem; } ; conv-hash = hash: if hash == "test" then "test" else builtins.convertHash { inherit hash; toHashFormat = "nix32"; } ; in builtins.listToAttrs (builtins.map (x: { name = x.id; value = conv-hash x.hash; }) drv)'
var 'expr', 'let drv = import ./runners { host-system = builtins.currentSystem; } ; hash-of = x: builtins.head (builtins.tail (builtins.match "([^:]+):(.*)" x.uid)) ; in builtins.listToAttrs (builtins.map (x: { name = x.id; value = hash-of x; }) drv)'
var 'wd', $source_dir
add_implicit_dependency runners_nix_inputs
end

generator.build(:nix_eval, 'out/executor/vTEST/data/all.json') do
var 'expr', 'let drv = import ./runners { host-system = builtins.currentSystem; } ; conv-hash = hash: if hash == "test" then "test" else builtins.convertHash { inherit hash; toHashFormat = "nix32"; } ; in builtins.listToAttrs (builtins.map (x: { name = x.id; value = [ (conv-hash x.hash) ]; }) drv)'
var 'expr', 'let drv = import ./runners { host-system = builtins.currentSystem; } ; hash-of = x: builtins.head (builtins.tail (builtins.match "([^:]+):(.*)" x.uid)) ; in builtins.listToAttrs (builtins.map (x: { name = x.id; value = [ (hash-of x) ]; }) drv)'
var 'wd', $source_dir
add_implicit_dependency runners_nix_inputs
end

generator.build(:phony, 'all/data') do
Expand Down
Loading
Loading