Public release release-b8454b34d38c

Source commit: b8454b34d38cc2ba0bd278e842060db45d091e1c

Public tree identity: sha256:69d6c8143bf6227e1bb07852aa94e8af9c26793eca252bb46788894f728cb6d2
This commit is contained in:
Clusterflux release 2026-07-19 09:43:54 +02:00
commit d2e84229c5
221 changed files with 80960 additions and 0 deletions

View file

@ -0,0 +1,16 @@
[package]
name = "runtime-conformance"
version = "0.1.0"
edition.workspace = true
license.workspace = true
repository.workspace = true
publish = false
[lib]
crate-type = ["rlib", "cdylib"]
[dependencies]
clusterflux = { package = "clusterflux-sdk", path = "../../../crates/clusterflux-sdk" }
futures-executor.workspace = true
serde.workspace = true
serde_json.workspace = true

View file

@ -0,0 +1,5 @@
# Runtime conformance fixture
This is test-only coverage for raw task ABI, cancellation, long joins, placement,
debug probes, and failure injection. It is intentionally not a public SDK
example. Start with examples/hello-build.

View file

@ -0,0 +1,3 @@
FROM docker.io/library/alpine:3.20
RUN apk add --no-cache build-base tar zstd
WORKDIR /workspace

View file

@ -0,0 +1,2 @@
# User-attached Windows development execution contract.
# This is not a managed untrusted Windows sandbox.

View file

@ -0,0 +1,6 @@
#include <stdio.h>
int main(void) {
puts("hello from a real Clusterflux build");
return 0;
}

View file

@ -0,0 +1,501 @@
use clusterflux::{Artifact, EnvRef, SourceSnapshot};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, clusterflux::TaskArg)]
pub struct BuildReport {
pub linux_thread: u64,
pub linux_parallel_thread: u64,
pub package_thread: u64,
pub linux_artifact: Artifact,
pub package_artifact: Artifact,
pub source: SourceSnapshot,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, clusterflux::TaskArg)]
pub struct PackageInput {
pub release_name: String,
pub source: SourceSnapshot,
pub executable: Option<Artifact>,
pub inputs: Vec<Artifact>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, clusterflux::TaskArg)]
pub struct IdentityProbeInput {
pub source: SourceSnapshot,
pub label: String,
pub delay_seconds: u64,
}
pub fn linux_env() -> EnvRef {
clusterflux::env!("linux")
}
pub fn windows_env() -> EnvRef {
clusterflux::env!("windows")
}
#[clusterflux::task(capabilities = "source_filesystem")]
pub async fn prepare_source() -> SourceSnapshot {
#[cfg(target_arch = "wasm32")]
{
return clusterflux::source::snapshot()
.await
.expect("the source task should snapshot the node checkout it was placed on");
}
#[cfg(not(target_arch = "wasm32"))]
SourceSnapshot {
digest: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
.to_owned(),
}
}
#[clusterflux::task(capabilities = "command")]
pub async fn compile_linux(source: SourceSnapshot) -> Artifact {
let _ = &source;
#[cfg(target_arch = "wasm32")]
{
let executable = clusterflux::fs::output_path("hello-clusterflux")
.expect("the executable output path should be task-local");
let output = clusterflux::command::Command::new("cc")
.args([
"-Os",
"-static",
"-s",
"fixture/hello-clusterflux.c",
"-o",
executable.as_str(),
])
.current_dir("/workspace")
.env("SOURCE_DATE_EPOCH", "0")
.timeout(std::time::Duration::from_secs(180))
.network_disabled()
.output()
.await
.expect("the declared Linux environment should provide a real C compiler");
assert_eq!(output.status_code, Some(0));
return clusterflux::fs::flush(&executable)
.await
.expect("the command-created executable should flush to node artifact storage");
}
#[cfg(not(target_arch = "wasm32"))]
Artifact {
id: "hello-clusterflux-native-test".to_owned(),
digest: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
.to_owned(),
size_bytes: 0,
}
}
#[clusterflux::task]
#[unsafe(no_mangle)]
pub extern "C" fn task_add_one(input: i32) -> i32 {
input + 1
}
#[clusterflux::task]
#[unsafe(no_mangle)]
pub extern "C" fn task_trap(_input: i32) -> i32 {
#[cfg(target_arch = "wasm32")]
core::arch::wasm32::unreachable();
#[cfg(not(target_arch = "wasm32"))]
panic!("intentional task trap")
}
#[clusterflux::task(capabilities = "command")]
pub async fn package_release(input: PackageInput) -> Artifact {
#[cfg(target_arch = "wasm32")]
{
assert_eq!(input.release_name, "release.tar");
let executable = input
.executable
.as_ref()
.expect("the package input should contain the compiler artifact");
assert!(input.inputs.iter().any(|artifact| artifact == executable));
let executable = clusterflux::fs::materialize(&executable, "package/hello-clusterflux")
.await
.expect("the retaining node should materialize the compiler artifact locally");
let release = clusterflux::fs::output_path("release.tar")
.expect("the release output path should be task-local");
let output = clusterflux::command::Command::new("tar")
.args([
"--sort=name",
"--mtime=@0",
"--owner=0",
"--group=0",
"--numeric-owner",
"--mode=0755",
"-cf",
release.as_str(),
"-C",
"/clusterflux/output/package",
"hello-clusterflux",
])
.current_dir("/workspace")
.env("SOURCE_DATE_EPOCH", "0")
.timeout(std::time::Duration::from_secs(180))
.network_disabled()
.output()
.await
.expect("the declared Linux environment should package the materialized executable");
assert_eq!(output.status_code, Some(0));
assert_eq!(
executable.as_str(),
"/clusterflux/output/package/hello-clusterflux"
);
return clusterflux::fs::flush(&release)
.await
.expect("the command-created release archive should flush as the final artifact");
}
#[cfg(not(target_arch = "wasm32"))]
{
let _ = input;
Artifact {
id: "release-native-test".to_owned(),
digest: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
.to_owned(),
size_bytes: 0,
}
}
}
#[clusterflux::task(capabilities = "command")]
pub async fn abort_probe(source: SourceSnapshot) -> i32 {
let _ = &source;
#[cfg(target_arch = "wasm32")]
{
let output = clusterflux::command::Command::new("sh")
.args(["-c", "sleep 90"])
.timeout(std::time::Duration::from_secs(120))
.network_disabled()
.output()
.await
.expect("abort probe command should either finish or be stopped by process abort");
return output.status_code.unwrap_or(-1);
}
#[cfg(not(target_arch = "wasm32"))]
0
}
#[clusterflux::task(capabilities = "command")]
pub async fn long_join_probe(source: SourceSnapshot) -> i32 {
let _ = &source;
#[cfg(target_arch = "wasm32")]
{
let output = clusterflux::command::Command::new("sh")
.args(["-c", "sleep 125"])
.timeout(std::time::Duration::from_secs(180))
.network_disabled()
.output()
.await
.expect("the controlled long-running command should complete normally");
return output.status_code.unwrap_or(-1);
}
#[cfg(not(target_arch = "wasm32"))]
0
}
#[clusterflux::task(capabilities = "command")]
pub async fn identity_probe(input: IdentityProbeInput) -> String {
let _ = &input.source;
#[cfg(target_arch = "wasm32")]
{
let script = format!(
"sleep {}; printf '%s' '{}'",
input.delay_seconds, input.label
);
let output = clusterflux::command::Command::new("sh")
.args(["-c", script.as_str()])
.timeout(std::time::Duration::from_secs(60))
.network_disabled()
.output()
.await
.expect("identity probe command should complete");
assert_eq!(output.status_code, Some(0));
return input.label;
}
#[cfg(not(target_arch = "wasm32"))]
input.label
}
#[clusterflux::task]
pub fn cooperative_cancellation_probe() -> i32 {
#[cfg(target_arch = "wasm32")]
loop {
if clusterflux::process::cancellation_requested()
.expect("task control should remain available while the Wasm task is running")
{
// Cancellation is a request observed and handled by task code. Returning
// normally is intentionally distinct from the runtime's forced abort path.
return 17;
}
}
#[cfg(not(target_arch = "wasm32"))]
17
}
#[clusterflux::task]
pub fn debug_child_probe() -> i32 {
#[cfg(target_arch = "wasm32")]
loop {
if clusterflux::process::cancellation_requested()
.expect("child debug participant should retain task control")
{
return 23;
}
}
#[cfg(not(target_arch = "wasm32"))]
23
}
#[clusterflux::task]
pub async fn debug_parent_probe() -> i32 {
#[cfg(target_arch = "wasm32")]
{
let child = clusterflux::spawn::task(debug_child_probe)
.name("debug child participant")
.start()
.await
.expect("parent debug participant should spawn its child");
return child
.join()
.await
.expect("parent debug participant should join its child");
}
#[cfg(not(target_arch = "wasm32"))]
23
}
#[clusterflux::main]
pub async fn build_main() -> BuildReport {
run_build_workflow().await
}
#[clusterflux::main(name = "fail")]
pub async fn fail_main() -> Result<i32, String> {
#[cfg(target_arch = "wasm32")]
{
let child = clusterflux::spawn::task_with_arg(0_i32, |value| task_trap(value))
.task_id("task_trap")
.name("intentional failing child")
.start()
.await
.map_err(|error| format!("failing entrypoint could not launch its child: {error}"))?;
return child
.join()
.await
.map_err(|error| format!("intentional child failure: {error}"));
}
#[cfg(not(target_arch = "wasm32"))]
Err("intentional child failure".to_owned())
}
#[clusterflux::main(name = "restart")]
pub async fn restart_main() -> i32 {
#[cfg(target_arch = "wasm32")]
{
return clusterflux::spawn::task_with_arg(0_i32, |value| task_trap(value))
.task_id("task_trap")
.name("edited restart probe")
.failure_policy(clusterflux::spawn::TaskFailurePolicy::AwaitOperator)
.start()
.await
.expect("restart probe should launch its child")
.join()
.await
.expect("restart probe child should complete");
}
#[cfg(not(target_arch = "wasm32"))]
task_add_one(41)
}
#[clusterflux::main(name = "park-wake")]
pub async fn park_wake_main() -> i32 {
#[cfg(target_arch = "wasm32")]
{
let mut value = 0_i32;
for _ in 0..16 {
let next = clusterflux::spawn::task_with_arg(value, |input| task_add_one(input))
.task_id("task_add_one")
.name("park/wake fuel refill probe")
.start()
.await
.expect("park/wake probe should launch")
.join()
.await
.expect("park/wake probe should complete");
value = i32::try_from(next).expect("park/wake result should remain in i32 range");
}
return value;
}
#[cfg(not(target_arch = "wasm32"))]
16
}
#[clusterflux::main(name = "long-join")]
pub async fn long_join_main() -> i32 {
#[cfg(target_arch = "wasm32")]
{
let source = clusterflux::spawn::async_task(prepare_source)
.name("prepare source for controlled long-running task")
.start()
.await
.expect("long join source preparation should launch")
.join()
.await
.expect("long join source preparation should complete");
return clusterflux::spawn::async_task_with_arg(source, long_join_probe)
.name("controlled task longer than two minutes")
.env(linux_env())
.start()
.await
.expect("long join probe should launch")
.join()
.await
.expect("long join probe should remain joinable beyond two minutes");
}
#[cfg(not(target_arch = "wasm32"))]
0
}
#[clusterflux::main(name = "identity")]
pub async fn identity_main() -> Vec<String> {
#[cfg(target_arch = "wasm32")]
{
let source = clusterflux::spawn::async_task(prepare_source)
.name("prepare source for identity probes")
.start()
.await
.expect("identity source preparation should launch")
.join()
.await
.expect("identity source preparation should complete");
let slow = clusterflux::spawn::async_task_with_arg(
IdentityProbeInput {
source: source.clone(),
label: "slow-first".to_owned(),
delay_seconds: 30,
},
identity_probe,
)
.name("identity probe slow")
.env(linux_env())
.start()
.await
.expect("slow identity probe should launch");
let fast = clusterflux::spawn::async_task_with_arg(
IdentityProbeInput {
source,
label: "fast-second".to_owned(),
delay_seconds: 20,
},
identity_probe,
)
.name("identity probe fast")
.env(linux_env())
.start()
.await
.expect("fast identity probe should launch");
let fast_result = fast
.join()
.await
.expect("fast identity probe should complete first");
let slow_result = slow
.join()
.await
.expect("slow identity probe should remain independently joinable");
return vec![fast_result, slow_result];
}
#[cfg(not(target_arch = "wasm32"))]
vec!["fast-second".to_owned(), "slow-first".to_owned()]
}
pub async fn run_build_workflow() -> BuildReport {
let source = clusterflux::spawn::async_task(prepare_source)
.name("prepare source snapshot")
.start()
.await
.unwrap()
.join()
.await
.unwrap();
let linux = clusterflux::spawn::async_task_with_arg(source.clone(), compile_linux)
.name("compile linux")
.env(linux_env())
.start()
.await
.unwrap();
let linux_parallel = clusterflux::spawn::async_task_with_arg(source.clone(), compile_linux)
.name("compile linux in parallel")
.env(linux_env())
.start()
.await
.unwrap();
let linux_thread = linux.virtual_thread_id();
let linux_parallel_thread = linux_parallel.virtual_thread_id();
let linux_artifact = linux.join().await.unwrap();
let linux_parallel_artifact = linux_parallel.join().await.unwrap();
assert_eq!(linux_artifact.digest, linux_parallel_artifact.digest);
let package = clusterflux::spawn::async_task_with_arg(
PackageInput {
release_name: "release.tar".to_owned(),
source: source.clone(),
executable: Some(linux_artifact.clone()),
inputs: vec![linux_artifact.clone()],
},
package_release,
)
.name("package artifacts")
.env(linux_env())
.start()
.await
.unwrap();
let package_thread = package.virtual_thread_id();
let package_artifact = package.join().await.unwrap();
BuildReport {
linux_thread,
linux_parallel_thread,
package_thread,
linux_artifact,
package_artifact,
source,
}
}
#[cfg(test)]
mod tests {
use futures_executor::block_on;
use super::*;
#[test]
fn flagship_workflow_is_rust_source_with_spawned_virtual_tasks() {
let main_report = block_on(build_main());
assert_eq!(
main_report.linux_artifact.id,
"hello-clusterflux-native-test"
);
assert_eq!(task_add_one(41), 42);
assert_eq!(block_on(restart_main()), 42);
assert_eq!(block_on(park_wake_main()), 16);
assert_eq!(block_on(long_join_main()), 0);
assert_eq!(
block_on(identity_main()),
vec!["fast-second".to_owned(), "slow-first".to_owned()]
);
assert_eq!(linux_env().name, "linux");
assert_eq!(windows_env().name, "windows");
let report = block_on(run_build_workflow());
assert_ne!(report.linux_thread, report.package_thread);
assert_ne!(report.linux_thread, report.linux_parallel_thread);
assert_eq!(report.linux_artifact.id, "hello-clusterflux-native-test");
assert_eq!(report.package_artifact.id, "release-native-test");
assert_eq!(
report.source.digest,
"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
);
}
}