Skip to content

feat(challenge-sdk-wasm): add term-challenge types, sandbox host functions, and extended trait - #41

Merged
echobt merged 5 commits into
mainfrom
feat/wasm-sdk-term-challenge-types
Feb 17, 2026
Merged

feat(challenge-sdk-wasm): add term-challenge types, sandbox host functions, and extended trait#41
echobt merged 5 commits into
mainfrom
feat/wasm-sdk-term-challenge-types

Conversation

@echobt

@echobt echobt commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Extends the WASM Guest SDK (challenge-sdk-wasm) with types, host function declarations, and trait methods needed to support terminal-based challenge evaluation workflows.

Changes

New types (types.rs)

  • TaskDefinition — describes a single evaluation task (id, description, command, expected output, timeout, scoring criteria)
  • SandboxExecRequest / SandboxExecResponse — structured request/response for executing commands in the host sandbox
  • TaskResult — per-task evaluation result with pass/fail, score, and optional output/metrics
  • TermEvaluationParams — structured deserialization target for EvaluationInput.params
  • Added details: Option<Vec<u8>> field to EvaluationOutput for carrying per-task result breakdowns
  • Added score_f64_scaled() helper to convert f64 scores to i64 with fixed-point scaling (×10000)

Host function declarations (host_functions.rs)

  • New platform_sandbox import module with extern "C" declarations:
    • sandbox_exec — execute a command in the host sandbox
    • get_timestamp — retrieve current timestamp for benchmarking
    • log_message — structured logging from WASM guest to host
  • Safe Rust wrappers: host_sandbox_exec, host_get_timestamp, host_log

Extended Challenge trait (lib.rs)

  • Added tasks() method (returns serialized task list, default empty)
  • Added configure() method (accepts config bytes, default no-op)
  • Updated register_challenge! macro to export get_tasks and configure as additional WASM ABI functions

Allocator fix (alloc_impl.rs)

  • Added allocate(size, _align) as a #[no_mangle] alias for alloc() to fix ABI mismatch where the validator calls allocate(size, 0) with two parameters
  • Made ARENA_SIZE configurable: default 1 MiB, large-arena feature flag for 4 MiB

Cargo.toml

  • Added default and large-arena feature flags

Summary by CodeRabbit

Release Notes

  • New Features
    • Added sandbox execution capabilities for challenge processing with request/response handling
    • Introduced task definitions and task result structures for challenge evaluation workflows
    • Added configurable memory arena sizes for WASM challenge modules
    • New Challenge trait methods for task retrieval and runtime configuration
    • Added host-level timestamp and logging functions for challenges
    • Enhanced evaluation output with optional details field

…ypes and host functions

Add term-challenge evaluation model support to the WASM guest SDK, enabling
challenge authors to define tasks, execute sandbox commands, and report
per-task scoring breakdowns.

New types (types.rs): TaskDefinition, SandboxExecRequest, SandboxExecResponse,
TaskResult, and TermEvaluationParams provide no_std-compatible structures for
task-based evaluation workflows. EvaluationOutput gains a `details` field for
serialized per-task result breakdowns. A score_f64_scaled() helper converts
f64 scores to i64 via fixed-point scaling (×10000).

New host functions (host_functions.rs): Declares sandbox_exec, get_timestamp,
and log_message under the platform_sandbox WASM import module, with safe Rust
wrappers host_sandbox_exec, host_get_timestamp, and host_log.

Extended Challenge trait (lib.rs): Adds optional tasks() and configure()
methods with default implementations. The register_challenge! macro now
exports get_tasks and configure as additional WASM ABI entry points.

Allocator fix (alloc_impl.rs): Adds allocate(size, _align) as a no_mangle
alias for alloc() to fix ABI mismatch where the validator calls with two
parameters. ARENA_SIZE is now configurable via the large-arena feature flag
(4 MiB when enabled, 1 MiB default).

Cargo.toml: Adds default and large-arena feature flags.
@coderabbitai

coderabbitai Bot commented Feb 17, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@echobt has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 21 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

The pull request extends the WASM challenge SDK with sandbox execution infrastructure, task management capabilities, and configurable memory allocation. New types define task structures, sandbox request/response formats, and evaluation parameters. The Challenge trait gains tasks() and configure() methods with corresponding C ABI exports. FFI bindings enable platform sandbox operations, timestamp retrieval, and logging. Memory arena size becomes feature-gated (default 1 MiB, optional 4 MiB). The EvaluationOutput type gains an optional details field.

Changes

Cohort / File(s) Summary
Evaluation Output Enhancement
challenges/term-challenge/src/evaluation.rs, crates/challenge-sdk-wasm/src/types.rs
Added optional details: Option<Vec<u8>> field to EvaluationOutput struct with builder method with_details() and updated constructors to initialize field.
Memory Arena Configuration
crates/challenge-sdk-wasm/Cargo.toml, crates/challenge-sdk-wasm/src/alloc_impl.rs
Introduced [features] section with default = [] and large-arena = [] flags; conditionally set ARENA_SIZE to 1 MiB or 4 MiB based on feature. Added public C ABI allocate(size: i32, _align: i32) -> i32 function delegating to alloc().
Sandbox Execution Layer
crates/challenge-sdk-wasm/src/host_functions.rs
Added FFI bindings for platform_sandbox module (sandbox_exec, get_timestamp, log_message) and public wrapper functions: host_sandbox_exec() executes requests in sandbox, host_get_timestamp() fetches timestamps, host_log() logs messages at specified levels.
Type System Expansion
crates/challenge-sdk-wasm/src/types.rs
Introduced new public structs: TaskDefinition, SandboxExecRequest, SandboxExecResponse (with is_success() method), TaskResult (with success() and failure() helpers), and TermEvaluationParams. Added score_f64_scaled(value: f64) -> i64 utility function.
Challenge Trait Extension
crates/challenge-sdk-wasm/src/lib.rs
Added default trait methods tasks() -> Vec<u8> and configure(&self, _config: &[u8]) to Challenge. Expanded public re-exports to include new types. Added C ABI functions get_tasks() -> i64 and configure(config_ptr: i32, config_len: i32) -> i32 via macro, delegating to trait methods.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 A sandbox sprouts where tasks now bloom,
With memory to spare in the WASM room,
Details flow through evaluation's stream,
Features gated, a flexible dream!
The SDK grows, more powers to weave,
Hops of joy—what a day to believe!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding term-challenge types, sandbox host functions, and extending the Challenge trait in the challenge-sdk-wasm crate.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/wasm-sdk-term-challenge-types

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
crates/challenge-sdk-wasm/src/alloc_impl.rs (1)

57-60: Silently ignoring _align may mask future bugs.

The PR notes the validator currently passes 0 for alignment, so delegating to alloc (hardcoded align=8) is fine today. However, if a future host ever supplies a real alignment value, this will silently use 8-byte alignment instead, which could lead to subtle memory-alignment issues. Consider at minimum a debug assertion or a comment in the function body documenting why _align is intentionally ignored.

💡 Suggested documentation
 #[no_mangle]
 pub extern "C" fn allocate(size: i32, _align: i32) -> i32 {
+    // NOTE: _align is intentionally ignored. The validator currently passes 0;
+    // `alloc` always uses 8-byte alignment which satisfies all WASM types.
     alloc(size)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/challenge-sdk-wasm/src/alloc_impl.rs` around lines 57 - 60, The
allocate function currently ignores the _align parameter and always calls
alloc(size) (which uses a hardcoded 8-byte alignment); add a short justification
and safety check: either add a comment explaining that hosts currently pass 0
alignment and 8-byte alignment is intentional, or add a debug assertion (e.g.,
debug_assert!(_align == 0 || _align == 8)) to catch unexpected non-zero align
values in debug builds, and keep the existing call to alloc(size) to preserve
current behavior; update the allocate function (symbol: allocate) to include
this comment/assertion referencing alloc so future changes are explicit.
crates/challenge-sdk-wasm/src/lib.rs (1)

30-35: configure() returns () — no way to signal failure to the host.

setup_environment (line 27) returns bool to indicate success/failure, and the ABI wrapper (line 178) propagates it. In contrast, configure returns (), and the ABI wrapper (line 207) unconditionally returns 1. If a challenge implementation encounters bad config, it cannot communicate this to the host.

If configuration can fail, consider aligning with setup_environment:

💡 Suggested change
-    fn configure(&self, _config: &[u8]) {}
+    fn configure(&self, _config: &[u8]) -> bool { true }

And in the macro:

         #[no_mangle]
         pub extern "C" fn configure(config_ptr: i32, config_len: i32) -> i32 {
             let slice = unsafe {
                 core::slice::from_raw_parts(config_ptr as *const u8, config_len as usize)
             };
-            <$ty as $crate::Challenge>::configure(&_CHALLENGE, slice);
-            1
+            if <$ty as $crate::Challenge>::configure(&_CHALLENGE, slice) {
+                1
+            } else {
+                0
+            }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/challenge-sdk-wasm/src/lib.rs` around lines 30 - 35, The
configure(&self, _config: &[u8]) function currently returns () so callers/host
cannot know if configuration failed; change its signature to return a bool (or
other simple failure indicator) like setup_environment does, update the
challenge implementation(s) to return false on bad config, and update the
macro-generated ABI wrapper that currently unconditionally returns 1 to
propagate the configure return value (i.e., convert the bool into the ABI
return) so failures are visible to the host; ensure you update any places
referencing configure (and the macro that emits the ABI wrapper) to match the
new signature.
crates/challenge-sdk-wasm/src/types.rs (1)

55-57: score_f64_scaled silently converts NaN to 0 and saturates on infinity.

The as i64 cast is well-defined in Rust (saturating semantics since 1.45), but NaN inputs silently become a score of 0 and ±Infinity saturates to i64::MAX/i64::MIN. In a scoring context, these likely indicate upstream bugs that should surface as errors rather than be silently accepted.

💡 Suggested defensive variant
 pub fn score_f64_scaled(value: f64) -> i64 {
+    debug_assert!(value.is_finite(), "score_f64_scaled received non-finite value: {}", value);
     (value * 10_000.0) as i64
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/challenge-sdk-wasm/src/types.rs` around lines 55 - 57, The function
score_f64_scaled currently casts with "as i64" which silently maps NaN to 0 and
infinities to i64::MIN/MAX; change score_f64_scaled to validate the input first
(use value.is_nan() and value.is_finite()) and return a Result<i64, E> (or
Option<i64>) instead of silently converting, returning an Err with a clear
message for NaN or ±Infinity; multiply by 10_000.0 only after validating and
then perform the safe cast (or saturating/clamping explicitly if you prefer
exact semantics) so callers can handle invalid upstream scores.
crates/challenge-sdk-wasm/src/host_functions.rs (1)

187-217: New sandbox host functions follow established patterns — looks good.

The implementations of host_sandbox_exec, host_get_timestamp, and host_log are consistent with the existing host function wrappers in this file.

One point worth noting: host_get_timestamp() (line 211, via platform_sandbox) coexists with host_get_time() (line 175, via platform_terminal). Consider adding a brief doc comment to each clarifying which context they serve, so downstream challenge authors pick the right one.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/challenge-sdk-wasm/src/host_functions.rs` around lines 187 - 217, Add
brief doc comments to distinguish the two time-related host functions so users
know which context to use: annotate host_get_time() (platform_terminal) and
host_get_timestamp() (platform_sandbox) with one-line comments describing their
source (platform_terminal vs platform_sandbox) and intended usage (e.g.,
terminal-restricted vs sandbox host-provided timestamp) placed directly above
each function definition to make the difference clear to downstream challenge
authors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/challenge-sdk-wasm/src/alloc_impl.rs`:
- Around line 57-60: The allocate function currently ignores the _align
parameter and always calls alloc(size) (which uses a hardcoded 8-byte
alignment); add a short justification and safety check: either add a comment
explaining that hosts currently pass 0 alignment and 8-byte alignment is
intentional, or add a debug assertion (e.g., debug_assert!(_align == 0 || _align
== 8)) to catch unexpected non-zero align values in debug builds, and keep the
existing call to alloc(size) to preserve current behavior; update the allocate
function (symbol: allocate) to include this comment/assertion referencing alloc
so future changes are explicit.

In `@crates/challenge-sdk-wasm/src/host_functions.rs`:
- Around line 187-217: Add brief doc comments to distinguish the two
time-related host functions so users know which context to use: annotate
host_get_time() (platform_terminal) and host_get_timestamp() (platform_sandbox)
with one-line comments describing their source (platform_terminal vs
platform_sandbox) and intended usage (e.g., terminal-restricted vs sandbox
host-provided timestamp) placed directly above each function definition to make
the difference clear to downstream challenge authors.

In `@crates/challenge-sdk-wasm/src/lib.rs`:
- Around line 30-35: The configure(&self, _config: &[u8]) function currently
returns () so callers/host cannot know if configuration failed; change its
signature to return a bool (or other simple failure indicator) like
setup_environment does, update the challenge implementation(s) to return false
on bad config, and update the macro-generated ABI wrapper that currently
unconditionally returns 1 to propagate the configure return value (i.e., convert
the bool into the ABI return) so failures are visible to the host; ensure you
update any places referencing configure (and the macro that emits the ABI
wrapper) to match the new signature.

In `@crates/challenge-sdk-wasm/src/types.rs`:
- Around line 55-57: The function score_f64_scaled currently casts with "as i64"
which silently maps NaN to 0 and infinities to i64::MIN/MAX; change
score_f64_scaled to validate the input first (use value.is_nan() and
value.is_finite()) and return a Result<i64, E> (or Option<i64>) instead of
silently converting, returning an Err with a clear message for NaN or ±Infinity;
multiply by 10_000.0 only after validating and then perform the safe cast (or
saturating/clamping explicitly if you prefer exact semantics) so callers can
handle invalid upstream scores.

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