Skip to content

test(huntsman-integration): Add neural network tasks. - #377

Merged
LinZhihao-723 merged 19 commits into
y-scope:mainfrom
sitaowang1998:e2e-nn
Jul 8, 2026
Merged

test(huntsman-integration): Add neural network tasks.#377
LinZhihao-723 merged 19 commits into
y-scope:mainfrom
sitaowang1998:e2e-nn

Conversation

@sitaowang1998

@sitaowang1998 sitaowang1998 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR adds in example/huntsman/nn three components:

  • core: Neural network neuron functions.
  • tasks: Spider task wrapper for neuron functions.

Checklist

  • The PR satisfies the contribution guidelines.
  • This is a breaking change and that has been indicated in the PR title, OR this isn't a
    breaking change.
  • Necessary docs have been updated, OR no docs need to be updated.

Validation performed

  • Add unit tests for neuron tasks.
  • Add a unit test to check that client correctly wire all inner tasks' outputs.
  • Add a client that runs a random neural network task graph on a Spider instance on baker and verify the result. The test code is in another branch.
  • GitHub workflows pass.

Summary by CodeRabbit

Summary

  • New Features

    • Added new neural-network example crates to the workspace: one for deterministic neuron math and one that exposes dense-layer tasks.
    • Provided three exported dense task variants (ReLU, sigmoid, identity) that compute a weighted sum plus bias and apply the selected activation.
  • Tests

    • Added unit tests validating activations, weighted-sum behavior, and dense-layer outputs (including ReLU clamping).

@sitaowang1998
sitaowang1998 requested a review from a team as a code owner July 7, 2026 20:02
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This change adds two new Rust crates to the workspace: huntsman-nn-core, which implements deterministic neuron activation and dense-layer computations with unit tests, and huntsman-nn-tasks, which exposes those computations as registered TDL tasks under the nn package.

Changes

Huntsman NN example

Layer / File(s) Summary
Neuron math core library and workspace wiring
Cargo.toml, examples/huntsman/nn/core/Cargo.toml, examples/huntsman/nn/core/src/lib.rs
Registers the new workspace members and adds the huntsman-nn-core crate with constants, activation functions, dense-layer helpers, and unit tests.
TDL task package wrapping core functions
examples/huntsman/nn/tasks/Cargo.toml, examples/huntsman/nn/tasks/src/lib.rs
Adds the huntsman-nn-tasks crate manifest, defines three TDL task functions that forward 25 inputs to the core helpers, and registers them in package nn.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding neural network tasks for the huntsman integration test setup.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
examples/huntsman/nn/tasks/src/lib.rs (1)

5-112: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reduce duplication in the NN task wrappers The three task functions repeat the same 25-argument list and hardcode the fan-in separately from huntsman_nn_core::NUM_INPUTS. A small local macro or a single composite parameter would remove the manual sync point.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/huntsman/nn/tasks/src/lib.rs` around lines 5 - 112, Reduce
duplication in the NN task wrappers by removing the repeated 25-argument
signatures in dense_relu, dense_sigmoid, and dense_identity and stop hardcoding
the fan-in separately from huntsman_nn_core::NUM_INPUTS. Refactor the task_decl
module with a small local macro or a single composite input parameter so all
three task functions share one source of truth for the input count and stay in
sync with huntsman_nn_core::NUM_INPUTS.
examples/huntsman/nn/client/src/main.rs (3)

391-398: 🩺 Stability & Availability | 🔵 Trivial

No cleanup of the created resource group after the job finishes.

Each run creates a new resource group (huntsman-nn-<random>) that is never removed, regardless of job outcome. For an example client intended for repeated validation runs (e.g., against a shared instance), this will accumulate orphaned resource groups over time.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/huntsman/nn/client/src/main.rs` around lines 391 - 398, The Huntsman
NN client creates a random resource group via add_resource_group and never
removes it, leaving orphaned groups after each run. Update main to clean up the
created resource group in a finally-style path after the job completes, using
the resource_group_id returned from add_resource_group and ensuring the cleanup
runs whether the job succeeds or fails.

432-456: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test only covers generate_topology, not build_graph's wiring translation.

inner_layer_wiring_covers_previous_layer validates the raw topology coverage guarantee, but doesn't assert that build_graph correctly maps Layer::wiring indices into TaskInputOutputIndex sources (i.e., that prev_layer[src] wiring lines up with simulate's layer_outputs[sources[k]]). Given the PR objective calls out a test that verifies "the client correctly wires the outputs of inner tasks," a test exercising build_graph against a small fixed topology would close this gap.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/huntsman/nn/client/src/main.rs` around lines 432 - 456, The current
test only verifies generate_topology coverage and does not exercise
build_graph’s wiring translation. Add or update a test around build_graph (and
its use of simulate / layer_outputs) with a small fixed topology so it
explicitly checks that Layer::wiring indices are mapped into the correct
TaskInputOutputIndex sources for inner tasks. Use the existing
inner_layer_wiring_covers_previous_layer test as a reference point, but assert
the constructed graph’s wiring, not just the raw topology.

90-99: 📐 Maintainability & Code Quality | 🔵 Trivial

Consider modelling layer-0 vs. inner layers structurally instead of Option + .expect().

Layer::wiring being Option<Vec<Vec<usize>>> pushes .expect("inner layer wiring is set") into three separate call sites (build_graph, simulate, and implicitly relied upon in generate_topology). An enum distinguishing Layer0/Inner(wiring) (or splitting topology[0] out as its own value at construction) would make the "layer 0 has no wiring" invariant unrepresentable-by-construction and remove the repeated panics.

♻️ Sketch of an alternative modelling
enum LayerWiring {
    Input,
    Wired(Vec<Vec<usize>>),
}

struct Layer {
    activation: Activation,
    wiring: LayerWiring,
}

build_graph/simulate would then match on LayerWiring instead of calling .expect(...).

Also applies to: 117-143, 157-203, 228-251

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/huntsman/nn/client/src/main.rs` around lines 90 - 99, The
`Layer::wiring` design still encodes layer-0 as `Option` and forces repeated
`.expect("inner layer wiring is set")` handling in `build_graph`, `simulate`,
and `generate_topology`. Refactor `Layer` to make the invariant explicit by
introducing a dedicated wiring type such as `LayerWiring::Input` and
`LayerWiring::Wired(...)`, or by splitting the first layer out at construction.
Update the affected methods to `match` on the new type instead of unwrapping, so
the layer-0 vs inner-layer distinction is represented structurally.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/huntsman/nn/client/src/main.rs`:
- Around line 278-298: The poll loop in poll_until_terminal can run forever
because it has no overall timeout or retry limit. Update poll_until_terminal to
enforce a bounded wait, using a timeout or max-attempts around the existing
get_job_state loop and tokio::time::sleep delay, and return an anyhow error when
the job never reaches a terminal JobState. Keep the fix localized to
poll_until_terminal and any callers that depend on its behavior so CI and
validation runs fail clearly instead of hanging.

---

Nitpick comments:
In `@examples/huntsman/nn/client/src/main.rs`:
- Around line 391-398: The Huntsman NN client creates a random resource group
via add_resource_group and never removes it, leaving orphaned groups after each
run. Update main to clean up the created resource group in a finally-style path
after the job completes, using the resource_group_id returned from
add_resource_group and ensuring the cleanup runs whether the job succeeds or
fails.
- Around line 432-456: The current test only verifies generate_topology coverage
and does not exercise build_graph’s wiring translation. Add or update a test
around build_graph (and its use of simulate / layer_outputs) with a small fixed
topology so it explicitly checks that Layer::wiring indices are mapped into the
correct TaskInputOutputIndex sources for inner tasks. Use the existing
inner_layer_wiring_covers_previous_layer test as a reference point, but assert
the constructed graph’s wiring, not just the raw topology.
- Around line 90-99: The `Layer::wiring` design still encodes layer-0 as
`Option` and forces repeated `.expect("inner layer wiring is set")` handling in
`build_graph`, `simulate`, and `generate_topology`. Refactor `Layer` to make the
invariant explicit by introducing a dedicated wiring type such as
`LayerWiring::Input` and `LayerWiring::Wired(...)`, or by splitting the first
layer out at construction. Update the affected methods to `match` on the new
type instead of unwrapping, so the layer-0 vs inner-layer distinction is
represented structurally.

In `@examples/huntsman/nn/tasks/src/lib.rs`:
- Around line 5-112: Reduce duplication in the NN task wrappers by removing the
repeated 25-argument signatures in dense_relu, dense_sigmoid, and dense_identity
and stop hardcoding the fan-in separately from huntsman_nn_core::NUM_INPUTS.
Refactor the task_decl module with a small local macro or a single composite
input parameter so all three task functions share one source of truth for the
input count and stay in sync with huntsman_nn_core::NUM_INPUTS.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 61b5e0eb-663e-45f6-a79d-5a619d68fae3

📥 Commits

Reviewing files that changed from the base of the PR and between 64345cd and 910371a.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • Cargo.toml
  • examples/huntsman/nn/client/Cargo.toml
  • examples/huntsman/nn/client/src/main.rs
  • examples/huntsman/nn/core/Cargo.toml
  • examples/huntsman/nn/core/src/lib.rs
  • examples/huntsman/nn/tasks/Cargo.toml
  • examples/huntsman/nn/tasks/src/lib.rs

Comment thread examples/huntsman/nn/client/src/main.rs Outdated
Comment on lines +278 to +298
/// Periodically polls the job state until it reaches a terminal state.
///
/// # Returns
///
/// The terminal [`JobState`] on success.
///
/// # Errors
///
/// Forwards [`SpiderClient::get_job_state`]'s return values on failure.
async fn poll_until_terminal(client: &SpiderClient, job_id: JobId) -> anyhow::Result<JobState> {
loop {
let state = client
.get_job_state(job_id)
.await
.context("get_job_state")?;
if state.is_terminal() {
return Ok(state);
}
tokio::time::sleep(Duration::from_millis(500)).await;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Unbounded polling loop can hang the client forever.

poll_until_terminal loops with no maximum attempt count or overall timeout — if the job never reaches a terminal JobState (e.g., Spider gets stuck or a worker crashes mid-job), this validation client will block indefinitely instead of failing with a clear error. This is especially relevant for CI or automated validation runs mentioned in the PR description.

🛠️ Suggested fix: bound the poll loop
-async fn poll_until_terminal(client: &SpiderClient, job_id: JobId) -> anyhow::Result<JobState> {
-    loop {
+async fn poll_until_terminal(
+    client: &SpiderClient,
+    job_id: JobId,
+    max_attempts: usize,
+) -> anyhow::Result<JobState> {
+    for _ in 0..max_attempts {
         let state = client
             .get_job_state(job_id)
             .await
             .context("get_job_state")?;
         if state.is_terminal() {
             return Ok(state);
         }
         tokio::time::sleep(Duration::from_millis(500)).await;
     }
+    Err(anyhow!("timed out waiting for job {} to reach a terminal state", job_id.get()))
 }

Also applies to: 411-413

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/huntsman/nn/client/src/main.rs` around lines 278 - 298, The poll
loop in poll_until_terminal can run forever because it has no overall timeout or
retry limit. Update poll_until_terminal to enforce a bounded wait, using a
timeout or max-attempts around the existing get_job_state loop and
tokio::time::sleep delay, and return an anyhow error when the job never reaches
a terminal JobState. Keep the fix localized to poll_until_terminal and any
callers that depend on its behavior so CI and validation runs fail clearly
instead of hanging.

@sitaowang1998 sitaowang1998 changed the title test(huntsman-integration): Add neural network tasks and a client to run integration test using these tasks. test(huntsman-integration): Add neural network tasks. Jul 8, 2026
Comment on lines +10 to +14
/// (`WEIGHTS[k] = (k + 1) * 0.01 * (-1)^k`), alternating in sign starting positive.
pub const WEIGHTS: [f64; NUM_INPUTS] = [
0.01, -0.02, 0.03, -0.04, 0.05, -0.06, 0.07, -0.08, 0.09, -0.10, 0.11, -0.12, 0.13, -0.14,
0.15, -0.16, 0.17, -0.18, 0.19, -0.20, 0.21, -0.22, 0.23, -0.24, 0.25,
];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Added negative values.

use spider_tdl::r#std::double;
use spider_tdl::task;

#[task(name = "neuron::dense_relu")]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Renaming nn -> neuron:

  • The package name is already nn.
  • These tasks are actual simulated "neuron"s

@LinZhihao-723
LinZhihao-723 merged commit a1d05e8 into y-scope:main Jul 8, 2026
17 checks passed
@sitaowang1998
sitaowang1998 deleted the e2e-nn branch July 8, 2026 21:40
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.

2 participants