This file is the agent-facing reference for the current IO runtime surface.
Source of truth is the current repository state in std/*.aic and runtime lowering in compiler/aic/libs/backend_llvm/src/main.aic.
It includes the direct IO primitives plus the current control-plane modules used by app startup and request dispatch (std.http_server, std.router, and std.config).
Covered modules:
std.iostd.error_contextstd.fsstd.envstd.pathstd.procstd.netstd.poolstd.tlsstd.timestd.signalstd.randstd.retrystd.setstd.logstd.bufferstd.cryptostd.configstd.http_serverstd.router
- Human-readable matrix:
docs/numeric-api-adoption-wave5.md. - Machine-readable matrix:
docs/numeric-api-adoption-wave5.json. - Prior fixed-width scalar baseline:
docs/io-fixed-width-taxonomy-wave2.md.
- Wave 5D example markers:
wave5_migration_buffer_u32,wave5_numeric_end_to_end. - Canonical verification snippet style uses explicit test-suite selection:
cargo test --locked --test <suite> <case>. - Numeric drift + command policy guard reference:
tests/unit_tests.rs(unit_wave5d_docs_examples_and_command_policy_markers_are_present). - Docs/examples CI wiring guard reference:
tests/agent_recipe_tests.rs(wave5d_numeric_docs_examples_and_ci_policy_are_consistent).
Known effects (from compiler/aic/libs/typecheck/src/main.aic):
iofsnettimerandenvprocconcurrency
Typechecking enforces direct and transitive effect declarations (E2001, E2005).
The backend maps runtime status codes to typed error enums in compiler/aic/libs/backend_llvm/src/main.aic.
| Module | Status-to-variant mapping |
|---|---|
IoError |
1=EndOfInput, 2=InvalidInput, 3=Io |
FsError |
1=NotFound, 2=PermissionDenied, 3=AlreadyExists, 4=InvalidInput, 5=Io |
EnvError |
1=NotFound, 2=PermissionDenied, 3=InvalidInput, 4=Io |
ProcError |
1=NotFound, 2=PermissionDenied, 3=InvalidInput, 4=Io, 5=UnknownProcess |
NetError |
1=NotFound, 2=PermissionDenied, 3=Refused, 4=Timeout, 5=AddressInUse, 6=InvalidInput, 7=Io, 8=ConnectionClosed |
TlsError |
1=HandshakeFailed, 2=CertificateInvalid, 3=CertificateExpired, 4=HostnameMismatch, 5=ProtocolError, 6=ConnectionClosed, 7=Io, 8=Timeout |
TimeError |
1=InvalidFormat, 2=InvalidDate, 3=InvalidTime, 4=InvalidOffset, 5=InvalidInput, 6=Internal |
SignalError |
1=UnsupportedPlatform, 2=InvalidSignal, 3=PermissionDenied, 4=Internal |
BufferError |
1=Underflow, 2=Overflow, 3=InvalidUtf8, 4=InvalidInput |
CryptoError |
1=InvalidInput, 2=UnsupportedAlgorithm, 3=Internal |
enum IoError {
EndOfInput,
InvalidInput,
Io,
}
type IoErrorContext = ErrorContext[IoError]
fn print_int(x: Int) -> () effects { io }
fn print_str(x: String) -> () effects { io }
fn print_float(x: Float) -> () effects { io }
fn read_line() -> Result[String, IoError] effects { io }
fn read_int() -> Result[Int, IoError] effects { io }
fn read_char() -> Result[String, IoError] effects { io }
fn prompt(message: String) -> Result[String, IoError] effects { io }
fn eprint_str(x: String) -> () effects { io }
fn eprint_int(x: Int) -> () effects { io }
fn println_str(x: String) -> () effects { io }
fn println_int(x: Int) -> () effects { io }
fn print_bool(x: Bool) -> () effects { io }
fn println_bool(x: Bool) -> () effects { io }
fn flush_stdout() -> () effects { io }
fn flush_stderr() -> () effects { io }
fn panic(message: String) -> () effects { io }
fn from_fs_error(err: FsError) -> IoError
fn from_net_error(err: NetError) -> IoError
fn from_proc_error(err: ProcError) -> IoError
fn from_env_error(err: EnvError) -> IoError
fn from_fs_error_with_context(err: FsError, context: String) -> IoErrorContext
fn from_net_error_with_context(err: NetError, context: String) -> IoErrorContext
fn from_proc_error_with_context(err: ProcError, context: String) -> IoErrorContext
fn from_env_error_with_context(err: EnvError, context: String) -> IoErrorContext
fn io_error(ctx: IoErrorContext) -> IoError
Notes:
promptwrites the message, flushes stdout, then reads one line.read_charexpects a single UTF-8 scalar value from one input line.- Existing
Result[..., IoError]APIs are unchanged; context chaining is opt-in viafrom_*_error_with_context(...). - Context chain format is append-only and flattened as text (for example:
open config -> fs.NotFound -> io.EndOfInput -> bootstrap). - Reader/writer coverage is broader than the top-level print/read helpers:
Reader,Writer,MockReader,MockWriter,TcpReader,file_reader,file_writer,file_appender,tcp_connect_reader,tcp_connect_writer,read_stream,read_stream_optional,write_stream,flush_stream,close_reader,close_writer, andstream_copyare part of the current surface. - The mock APIs are intended for deterministic tests and agent fixtures, while
stream_copyis the stable adapter for reader-to-writer piping.
struct ErrorContext[E] {
error: E,
context: String,
chain: String,
}
fn new_error_context[E](error: E, context: String) -> ErrorContext[E]
fn with_context[E](ctx: ErrorContext[E], context: String) -> ErrorContext[E]
fn with_context_error[E](error: E, context: String) -> ErrorContext[E]
fn with_cause[E](error: E, context: String, cause: String) -> ErrorContext[E]
fn with_cause_context[E](ctx: ErrorContext[E], cause: String) -> ErrorContext[E]
fn error_value[E](ctx: ErrorContext[E]) -> E
fn error_chain[E](ctx: ErrorContext[E]) -> String
enum FsError {
NotFound,
PermissionDenied,
AlreadyExists,
InvalidInput,
Io,
}
struct FsMetadata {
is_file: Bool,
is_dir: Bool,
size: Int,
}
struct FileHandle {
handle: Int,
}
fn exists(path: String) -> Bool effects { fs }
fn read_text(path: String) -> Result[String, FsError] effects { fs }
fn write_text(path: String, content: String) -> Result[Bool, FsError] effects { fs }
fn append_text(path: String, content: String) -> Result[Bool, FsError] effects { fs }
fn copy(from_path: String, to_path: String) -> Result[Bool, FsError] effects { fs }
fn move(from_path: String, to_path: String) -> Result[Bool, FsError] effects { fs }
fn delete(path: String) -> Result[Bool, FsError] effects { fs }
fn metadata(path: String) -> Result[FsMetadata, FsError] effects { fs }
fn walk_dir(path: String) -> Result[Vec[String], FsError] effects { fs }
fn temp_file(prefix: String) -> Result[String, FsError] effects { fs }
fn temp_dir(prefix: String) -> Result[String, FsError] effects { fs }
fn read_bytes(path: String) -> Result[String, FsError] effects { fs }
fn write_bytes(path: String, content: String) -> Result[Bool, FsError] effects { fs }
fn append_bytes(path: String, content: String) -> Result[Bool, FsError] effects { fs }
fn open_read(path: String) -> Result[FileHandle, FsError] effects { fs }
fn open_write(path: String) -> Result[FileHandle, FsError] effects { fs }
fn open_append(path: String) -> Result[FileHandle, FsError] effects { fs }
fn file_read_line(file: FileHandle) -> Result[Option[String], FsError] effects { fs }
fn file_write_str(file: FileHandle, content: String) -> Result[Bool, FsError] effects { fs }
fn file_close(file: FileHandle) -> Result[Bool, FsError] effects { fs }
fn mkdir(path: String) -> Result[Bool, FsError] effects { fs }
fn mkdir_all(path: String) -> Result[Bool, FsError] effects { fs }
fn rmdir(path: String) -> Result[Bool, FsError] effects { fs }
fn list_dir(path: String) -> Result[Vec[String], FsError] effects { fs }
fn create_symlink(target_path: String, link_path: String) -> Result[Bool, FsError] effects { fs }
fn read_symlink(path: String) -> Result[String, FsError] effects { fs }
fn set_readonly(path: String, readonly: Bool) -> Result[Bool, FsError] effects { fs }
Notes:
- File-handle table capacity is bounded (
1024runtime slots). read_bytes/write_bytes/append_bytesare the binary-oriented boundary APIs.open_*andfile_*are the current handle lifecycle APIs; always pairopen_*withfile_close.walk_dircurrently exposes count-onlyVecpayload semantics in codegen; usevec_len(...)as the stable operation.list_dirreturns concrete directory entry strings.temp_fileandtemp_dirreturn absolute paths.create_symlink,read_symlink, andset_readonlyexpose platform-sensitive path metadata controls explicitly.- Windows caveats:
create_symlinkmay fail with privilege-related errors.read_symlinkcurrently returnsFsError::Io.
enum EnvError {
NotFound,
PermissionDenied,
InvalidInput,
Io,
}
struct EnvEntry {
key: String,
value: String,
}
fn get(key: String) -> Result[String, EnvError] effects { env }
fn set(key: String, value: String) -> Result[Bool, EnvError] effects { env }
fn remove(key: String) -> Result[Bool, EnvError] effects { env }
fn cwd() -> Result[String, EnvError] effects { env, fs }
fn set_cwd(path: String) -> Result[Bool, EnvError] effects { env, fs }
fn args() -> Vec[String] effects { env }
fn arg_count() -> Int effects { env }
fn arg_at(index: Int) -> Option[String] effects { env }
fn exit(code: Int32) -> () effects { env }
fn all_vars() -> Vec[EnvEntry] effects { env }
fn home_dir() -> Result[String, EnvError] effects { env, fs }
fn temp_dir() -> Result[String, EnvError] effects { env, fs }
fn os_name() -> String effects { env }
fn arch() -> String effects { env }
Notes:
- Invalid variable names (empty or containing
=) map toEnvError::InvalidInput. argsandall_varsreturn snapshots of process state at call time.home_dir,temp_dir,os_name, andarchare the stable metadata helpers used by config/bootstrap code.
These modules are part of the current IO-adjacent surface and are used by server startup, request dispatch, and configuration loading flows.
// std.http_server
fn listen(addr: String) -> Result[Int, ServerError] effects { net }
fn accept(listener: Int, timeout_ms: Int) -> Result[Int, ServerError] effects { net }
fn read_request(conn: Int, max_bytes: Int, timeout_ms: Int) -> Result[Request, ServerError] effects { net }
fn write_response(conn: Int, response: ResponseView) -> Result[Int, ServerError] effects { net }
fn close(handle: Int) -> Result[Bool, ServerError] effects { net }
fn response(status: UInt16, headers: Map[String, String], body: String) -> ResponseView
fn text_response(status: UInt16, body: String) -> ResponseView
fn json_response(status: UInt16, body: String) -> ResponseView
fn header(resp: ResponseView, name: String) -> Option[String]
// std.router
fn new_router() -> Result[Router, RouterError]
fn add(router: Router, method: String, pattern: String, route_id: Int) -> Result[Router, RouterError]
fn match_route(router: Router, method: String, path: String) -> Result[Option[RouteMatch], RouterError]
// std.config
fn load_json(path: String) -> Result[Map[String, String], ConfigError] effects { fs }
fn load_env_prefix(prefix: String) -> Map[String, String] effects { env }
fn get_or_default(config: Map[String, String], key: String, fallback: String) -> String
fn require(config: Map[String, String], key: String) -> Result[String, ConfigError]
Notes:
std.http_serverstays synchronous; it is the transport-side companion tostd.http.std.routerprovides deterministic route registration and matching for request dispatch.std.configcomposesstd.fs,std.json, andstd.envfor startup config loading without pretending to be a network API.- Current
std.mapexecution support coversmap.new_map,insert,get,values, andentriesforMap[K, V]withKinString/Int/BoolandVinString/Int/Bool/UInt64.
struct Set[T] {
items: Map[T, Int],
}
fn new_set[T]() -> Set[T]
fn add[T](s: Set[T], value: T) -> Set[T]
fn has[T](s: Set[T], value: T) -> Bool
fn discard[T](s: Set[T], value: T) -> Set[T]
fn set_size[T](s: Set[T]) -> Int
fn to_vec[T](s: Set[T]) -> Vec[T]
fn union[T](left: Set[T], right: Set[T]) -> Set[T]
fn intersection[T](left: Set[T], right: Set[T]) -> Set[T]
fn difference[T](left: Set[T], right: Set[T]) -> Set[T]
Notes:
add/has/discardare the supported mutator/query APIs.to_vecis deterministic and returns members in ascending key order.- Supported key specializations for map/set paths are
String,Bytes,Int,UInt64, andBool. - Unsupported key kinds remain deterministic and emit backend diagnostic
E5011with explicit key-support guidance.
enum LogLevel {
Debug,
Info,
Warn,
Error,
}
fn log(level: LogLevel, message: String) -> () effects { io }
fn debug(message: String) -> () effects { io }
fn info(message: String) -> () effects { io }
fn warn(message: String) -> () effects { io }
fn error(message: String) -> () effects { io }
fn set_level(level: LogLevel) -> () effects { io }
fn set_json_output(enabled: Bool) -> () effects { io }
Notes:
- Default runtime level is
Info;Debugis filtered until level is lowered. set_json_output(true)switches stderr output to JSON lines withlevel,msg,ts, andtrace_id.AIC_LOG_LEVELandAIC_LOG_JSONenvironment variables are read at runtime startup and can be overridden by API calls.
fn join(left: String, right: String) -> String
fn basename(path: String) -> String
fn dirname(path: String) -> String
fn extension(path: String) -> String
fn is_abs(path: String) -> Bool
Notes:
- Path helpers are pure (no effects).
joinreturnsrightdirectly whenrightis absolute.
enum ProcError {
NotFound,
PermissionDenied,
InvalidInput,
Io,
UnknownProcess,
}
type ProcHandle = UInt32
type ProcExitStatus = Int32
struct ProcResult {
status: ProcExitStatus,
stdout: String,
stderr: String,
}
struct RunOptions {
stdin: String,
cwd: String,
env: Vec[String],
timeout_ms: Int,
}
fn spawn(command: String) -> Result[ProcHandle, ProcError] effects { proc, env }
fn wait(handle: ProcHandle) -> Result[ProcExitStatus, ProcError] effects { proc }
fn kill(handle: ProcHandle) -> Result[Bool, ProcError] effects { proc }
fn run(command: String) -> Result[ProcResult, ProcError] effects { proc, env }
fn pipe(left: String, right: String) -> Result[ProcResult, ProcError] effects { proc, env }
fn run_with(command: String, options: RunOptions) -> Result[ProcResult, ProcError] effects { proc, env }
fn is_running(handle: ProcHandle) -> Result[Bool, ProcError] effects { proc }
fn current_pid() -> Result[ProcHandle, ProcError] effects { proc }
fn run_timeout(command: String, timeout_ms: Int) -> Result[ProcResult, ProcError] effects { proc, env }
fn pipe_chain(stages: Vec[String]) -> Result[ProcResult, ProcError] effects { proc, env }
Notes:
run/pipesuccess is about launch/execution plumbing; checkProcResult.statusfor command exit status.- Public wrappers validate runtime
Intvalues at boundary conversion points (UInt32handles andInt32exit status). - Spawned-handle table capacity is bounded (
64runtime slots). - Windows caveats:
- Process APIs are available on Windows, but
spawn,run,run_with,run_timeout,pipe, andpipe_chaincan still surfaceProcError::Iofor backend/runtime failures. wait,kill, andis_runningcan surfaceProcError::UnknownProcesswhen the handle is not valid on the current host.run_withenvironment overrides currently reject entries containing"or line breaks withProcError::InvalidInput.- Command behavior follows
cmd.exe /Csemantics for shell syntax and exit-status propagation.
- Process APIs are available on Windows, but
enum Signal {
SigInt,
SigTerm,
SigHup,
}
enum SignalError {
UnsupportedPlatform,
InvalidSignal,
PermissionDenied,
Internal,
}
fn register(signal: Signal) -> Result[Bool, SignalError] effects { proc }
fn register_shutdown_handlers() -> Result[Bool, SignalError] effects { proc }
fn wait_for_signal() -> Result[Signal, SignalError] effects { proc }
Notes:
- Runtime support is implemented for Linux/macOS only and handles
SIGINT,SIGTERM, andSIGHUP. - Windows and other non-Linux/macOS targets return
SignalError::UnsupportedPlatform. wait_for_signalblocks until one of the registered signals arrives.
enum NetError {
NotFound,
PermissionDenied,
Refused,
Timeout,
AddressInUse,
InvalidInput,
Io,
ConnectionClosed,
Cancelled,
}
struct UdpPacket {
from: String,
payload: Bytes,
}
struct TcpStream {
handle: Int,
}
struct AsyncIntOp {
handle: Int,
}
struct AsyncStringOp {
handle: Int,
}
struct AsyncIntSelection {
index: Int,
value: Int,
}
struct AsyncStringSelection {
index: Int,
payload: Bytes,
}
struct AsyncRuntimePressure {
active_ops: Int,
queue_depth: Int,
op_limit: Int,
queue_limit: Int,
}
struct AsyncRuntimePressureU32 {
active_ops: UInt32,
queue_depth: UInt32,
op_limit: UInt32,
queue_limit: UInt32,
}
fn tcp_listen(addr: String) -> Result[Int, NetError] effects { net }
fn tcp_local_addr(handle: Int) -> Result[String, NetError] effects { net }
fn tcp_accept(listener: Int, timeout_ms: Int) -> Result[Int, NetError] effects { net }
fn tcp_connect(addr: String, timeout_ms: Int) -> Result[Int, NetError] effects { net }
fn tcp_send(handle: Int, payload: Bytes) -> Result[Int, NetError] effects { net }
fn tcp_send_timeout(handle: Int, payload: Bytes, timeout_ms: Int) -> Result[Int, NetError] effects { net }
fn tcp_recv(handle: Int, max_bytes: Int, timeout_ms: Int) -> Result[Bytes, NetError] effects { net }
fn tcp_recv_u32(handle: Int, max_bytes: UInt32, timeout_ms: Int) -> Result[Bytes, NetError] effects { net }
fn tcp_close(handle: Int) -> Result[Bool, NetError] effects { net }
fn tcp_set_nodelay(handle: Int, enabled: Bool) -> Result[Bool, NetError] effects { net }
fn tcp_get_nodelay(handle: Int) -> Result[Bool, NetError] effects { net }
fn tcp_set_keepalive(handle: Int, enabled: Bool) -> Result[Bool, NetError] effects { net }
fn tcp_get_keepalive(handle: Int) -> Result[Bool, NetError] effects { net }
fn tcp_set_keepalive_idle_secs(handle: Int, idle_secs: Int) -> Result[Bool, NetError] effects { net }
fn tcp_set_keepalive_idle_secs_u32(handle: Int, idle_secs: UInt32) -> Result[Bool, NetError] effects { net }
fn tcp_get_keepalive_idle_secs(handle: Int) -> Result[Int, NetError] effects { net }
fn tcp_get_keepalive_idle_secs_u32(handle: Int) -> Result[UInt32, NetError] effects { net }
fn tcp_set_keepalive_interval_secs(handle: Int, interval_secs: Int) -> Result[Bool, NetError] effects { net }
fn tcp_set_keepalive_interval_secs_u32(handle: Int, interval_secs: UInt32) -> Result[Bool, NetError] effects { net }
fn tcp_get_keepalive_interval_secs(handle: Int) -> Result[Int, NetError] effects { net }
fn tcp_get_keepalive_interval_secs_u32(handle: Int) -> Result[UInt32, NetError] effects { net }
fn tcp_set_keepalive_count(handle: Int, probe_count: Int) -> Result[Bool, NetError] effects { net }
fn tcp_set_keepalive_count_u32(handle: Int, probe_count: UInt32) -> Result[Bool, NetError] effects { net }
fn tcp_get_keepalive_count(handle: Int) -> Result[Int, NetError] effects { net }
fn tcp_get_keepalive_count_u32(handle: Int) -> Result[UInt32, NetError] effects { net }
fn tcp_peer_addr(handle: Int) -> Result[String, NetError] effects { net }
fn tcp_shutdown(handle: Int) -> Result[Bool, NetError] effects { net }
fn tcp_shutdown_read(handle: Int) -> Result[Bool, NetError] effects { net }
fn tcp_shutdown_write(handle: Int) -> Result[Bool, NetError] effects { net }
fn tcp_set_send_buffer_size(handle: Int, size_bytes: Int) -> Result[Bool, NetError] effects { net }
fn tcp_set_send_buffer_size_u32(handle: Int, size_bytes: UInt32) -> Result[Bool, NetError] effects { net }
fn tcp_get_send_buffer_size(handle: Int) -> Result[Int, NetError] effects { net }
fn tcp_get_send_buffer_size_u32(handle: Int) -> Result[UInt32, NetError] effects { net }
fn tcp_set_recv_buffer_size(handle: Int, size_bytes: Int) -> Result[Bool, NetError] effects { net }
fn tcp_set_recv_buffer_size_u32(handle: Int, size_bytes: UInt32) -> Result[Bool, NetError] effects { net }
fn tcp_get_recv_buffer_size(handle: Int) -> Result[Int, NetError] effects { net }
fn tcp_get_recv_buffer_size_u32(handle: Int) -> Result[UInt32, NetError] effects { net }
fn tcp_stream(handle: Int) -> TcpStream
fn tcp_stream_send(stream: TcpStream, payload: Bytes) -> Result[Int, NetError] effects { net }
fn tcp_stream_send_timeout(stream: TcpStream, payload: Bytes, timeout_ms: Int) -> Result[Int, NetError] effects { net }
fn tcp_stream_recv(stream: TcpStream, max_bytes: Int, timeout_ms: Int) -> Result[Bytes, NetError] effects { net }
fn tcp_stream_recv_u32(stream: TcpStream, max_bytes: UInt32, timeout_ms: Int) -> Result[Bytes, NetError] effects { net }
fn tcp_stream_frame_len_be_u32(header: Bytes) -> Result[UInt32, NetError]
fn tcp_stream_recv_exact_deadline(stream: TcpStream, expected_bytes: Int, deadline_ms: Int) -> Result[Bytes, NetError] effects { net, time }
fn tcp_stream_recv_exact_deadline_u32(stream: TcpStream, expected_bytes: UInt32, deadline_ms: Int) -> Result[Bytes, NetError] effects { net, time }
fn tcp_stream_recv_exact(stream: TcpStream, expected_bytes: Int, timeout_ms: Int) -> Result[Bytes, NetError] effects { net, time }
fn tcp_stream_recv_exact_u32(stream: TcpStream, expected_bytes: UInt32, timeout_ms: Int) -> Result[Bytes, NetError] effects { net, time }
fn tcp_stream_recv_framed_deadline(stream: TcpStream, max_frame_bytes: Int, deadline_ms: Int) -> Result[Bytes, NetError] effects { net, time }
fn tcp_stream_recv_framed_deadline_u32(stream: TcpStream, max_frame_bytes: UInt32, deadline_ms: Int) -> Result[Bytes, NetError] effects { net, time }
fn tcp_stream_recv_framed(stream: TcpStream, max_frame_bytes: Int, timeout_ms: Int) -> Result[Bytes, NetError] effects { net, time }
fn tcp_stream_recv_framed_u32(stream: TcpStream, max_frame_bytes: UInt32, timeout_ms: Int) -> Result[Bytes, NetError] effects { net, time }
fn tcp_stream_close(stream: TcpStream) -> Result[Bool, NetError] effects { net }
fn tcp_stream_set_nodelay(stream: TcpStream, enabled: Bool) -> Result[Bool, NetError] effects { net }
fn tcp_stream_get_nodelay(stream: TcpStream) -> Result[Bool, NetError] effects { net }
fn tcp_stream_set_keepalive(stream: TcpStream, enabled: Bool) -> Result[Bool, NetError] effects { net }
fn tcp_stream_get_keepalive(stream: TcpStream) -> Result[Bool, NetError] effects { net }
fn tcp_stream_set_keepalive_idle_secs(stream: TcpStream, idle_secs: Int) -> Result[Bool, NetError] effects { net }
fn tcp_stream_set_keepalive_idle_secs_u32(stream: TcpStream, idle_secs: UInt32) -> Result[Bool, NetError] effects { net }
fn tcp_stream_get_keepalive_idle_secs(stream: TcpStream) -> Result[Int, NetError] effects { net }
fn tcp_stream_get_keepalive_idle_secs_u32(stream: TcpStream) -> Result[UInt32, NetError] effects { net }
fn tcp_stream_set_keepalive_interval_secs(stream: TcpStream, interval_secs: Int) -> Result[Bool, NetError] effects { net }
fn tcp_stream_set_keepalive_interval_secs_u32(stream: TcpStream, interval_secs: UInt32) -> Result[Bool, NetError] effects { net }
fn tcp_stream_get_keepalive_interval_secs(stream: TcpStream) -> Result[Int, NetError] effects { net }
fn tcp_stream_get_keepalive_interval_secs_u32(stream: TcpStream) -> Result[UInt32, NetError] effects { net }
fn tcp_stream_set_keepalive_count(stream: TcpStream, probe_count: Int) -> Result[Bool, NetError] effects { net }
fn tcp_stream_set_keepalive_count_u32(stream: TcpStream, probe_count: UInt32) -> Result[Bool, NetError] effects { net }
fn tcp_stream_get_keepalive_count(stream: TcpStream) -> Result[Int, NetError] effects { net }
fn tcp_stream_get_keepalive_count_u32(stream: TcpStream) -> Result[UInt32, NetError] effects { net }
fn tcp_stream_peer_addr(stream: TcpStream) -> Result[String, NetError] effects { net }
fn tcp_stream_shutdown(stream: TcpStream) -> Result[Bool, NetError] effects { net }
fn tcp_stream_shutdown_read(stream: TcpStream) -> Result[Bool, NetError] effects { net }
fn tcp_stream_shutdown_write(stream: TcpStream) -> Result[Bool, NetError] effects { net }
fn tcp_stream_set_send_buffer_size(stream: TcpStream, size_bytes: Int) -> Result[Bool, NetError] effects { net }
fn tcp_stream_set_send_buffer_size_u32(stream: TcpStream, size_bytes: UInt32) -> Result[Bool, NetError] effects { net }
fn tcp_stream_get_send_buffer_size(stream: TcpStream) -> Result[Int, NetError] effects { net }
fn tcp_stream_get_send_buffer_size_u32(stream: TcpStream) -> Result[UInt32, NetError] effects { net }
fn tcp_stream_set_recv_buffer_size(stream: TcpStream, size_bytes: Int) -> Result[Bool, NetError] effects { net }
fn tcp_stream_set_recv_buffer_size_u32(stream: TcpStream, size_bytes: UInt32) -> Result[Bool, NetError] effects { net }
fn tcp_stream_get_recv_buffer_size(stream: TcpStream) -> Result[Int, NetError] effects { net }
fn tcp_stream_get_recv_buffer_size_u32(stream: TcpStream) -> Result[UInt32, NetError] effects { net }
fn async_accept_submit(listener: Int, timeout_ms: Int) -> Result[AsyncIntOp, NetError] effects { net, concurrency }
fn async_tcp_send_submit(handle: Int, payload: Bytes) -> Result[AsyncIntOp, NetError] effects { net, concurrency }
fn async_tcp_recv_submit(handle: Int, max_bytes: Int, timeout_ms: Int) -> Result[AsyncStringOp, NetError] effects { net, concurrency }
fn async_tcp_recv_submit_u32(handle: Int, max_bytes: UInt32, timeout_ms: Int) -> Result[AsyncStringOp, NetError] effects { net, concurrency }
fn async_wait_int(op: AsyncIntOp, timeout_ms: Int) -> Result[Int, NetError] effects { net, concurrency }
fn async_wait_string(op: AsyncStringOp, timeout_ms: Int) -> Result[Bytes, NetError] effects { net, concurrency }
fn async_cancel_int(op: AsyncIntOp) -> Result[Bool, NetError] effects { net, concurrency }
fn async_cancel_string(op: AsyncStringOp) -> Result[Bool, NetError] effects { net, concurrency }
fn async_poll_int(op: AsyncIntOp) -> Result[Option[Int], NetError] effects { net, concurrency }
fn async_poll_string(op: AsyncStringOp) -> Result[Option[Bytes], NetError] effects { net, concurrency }
fn async_wait_many_int(ops: Vec[AsyncIntOp], timeout_ms: Int) -> Result[AsyncIntSelection, NetError] effects { net, concurrency, time }
fn async_wait_many_int_u32(ops: Vec[AsyncIntOp], timeout_ms: Int) -> Result[AsyncIntSelectionU32, NetError] effects { net, concurrency, time }
fn async_wait_many_string(ops: Vec[AsyncStringOp], timeout_ms: Int) -> Result[AsyncStringSelection, NetError] effects { net, concurrency, time }
fn async_wait_many_string_u32(ops: Vec[AsyncStringOp], timeout_ms: Int) -> Result[AsyncStringSelectionU32, NetError] effects { net, concurrency, time }
fn async_wait_any_int(op1: AsyncIntOp, op2: AsyncIntOp, timeout_ms: Int) -> Result[AsyncIntSelection, NetError] effects { net, concurrency, time }
fn async_wait_any_int_u32(op1: AsyncIntOp, op2: AsyncIntOp, timeout_ms: Int) -> Result[AsyncIntSelectionU32, NetError] effects { net, concurrency, time }
fn async_wait_any_string(op1: AsyncStringOp, op2: AsyncStringOp, timeout_ms: Int) -> Result[AsyncStringSelection, NetError] effects { net, concurrency, time }
fn async_wait_any_string_u32(op1: AsyncStringOp, op2: AsyncStringOp, timeout_ms: Int) -> Result[AsyncStringSelectionU32, NetError] effects { net, concurrency, time }
fn async_runtime_pressure() -> Result[AsyncRuntimePressure, NetError] effects { net, concurrency }
fn async_runtime_pressure_u32() -> Result[AsyncRuntimePressureU32, NetError] effects { net, concurrency }
fn async_shutdown() -> Result[Bool, NetError] effects { net, concurrency }
fn async_accept(listener: Int, timeout_ms: Int) -> Result[Int, NetError] effects { net, concurrency }
fn async_tcp_send(handle: Int, payload: Bytes, timeout_ms: Int) -> Result[Int, NetError] effects { net, concurrency }
fn async_tcp_recv(handle: Int, max_bytes: Int, timeout_ms: Int) -> Result[Bytes, NetError] effects { net, concurrency }
fn async_tcp_recv_u32(handle: Int, max_bytes: UInt32, timeout_ms: Int) -> Result[Bytes, NetError] effects { net, concurrency }
fn udp_bind(addr: String) -> Result[Int, NetError] effects { net }
fn udp_local_addr(handle: Int) -> Result[String, NetError] effects { net }
fn udp_send_to(handle: Int, addr: String, payload: Bytes) -> Result[Int, NetError] effects { net }
fn udp_recv_from(handle: Int, max_bytes: Int, timeout_ms: Int) -> Result[UdpPacket, NetError] effects { net }
fn udp_recv_from_u32(handle: Int, max_bytes: UInt32, timeout_ms: Int) -> Result[UdpPacket, NetError] effects { net }
fn udp_close(handle: Int) -> Result[Bool, NetError] effects { net }
fn dns_lookup(host: String) -> Result[String, NetError] effects { net }
fn dns_lookup_all(host: String) -> Result[Vec[String], NetError] effects { net }
fn dns_reverse(addr: String) -> Result[String, NetError] effects { net }
type NetPortU16 = UInt16
fn net_int_to_u16(value: Int) -> Result[NetPortU16, NetError]
fn net_u16_to_int(value: NetPortU16) -> Int
fn net_format_host_port(host: String, port: NetPortU16) -> String
fn net_parse_host_port(endpoint: String) -> Result[(String, NetPortU16), NetError]
fn tcp_connect_host_port(host: String, port: NetPortU16, timeout_ms: Int) -> Result[Int, NetError] effects { net }
fn tcp_listen_host_port(host: String, port: NetPortU16) -> Result[Int, NetError] effects { net }
fn udp_bind_host_port(host: String, port: NetPortU16) -> Result[Int, NetError] effects { net }
fn tcp_local_endpoint(handle: Int) -> Result[(String, NetPortU16), NetError] effects { net }
Notes:
- Network-handle table capacity is bounded (
128runtime slots). - Runtime handle limits are configurable at process start (invalid/out-of-range values fall back to defaults):
AIC_RT_LIMIT_FS_FILES(default/max:1024)AIC_RT_LIMIT_PROC_HANDLES(default/max:64)AIC_RT_LIMIT_NET_HANDLES(default/max:128)AIC_RT_LIMIT_NET_ASYNC_OPS(default/max:512)AIC_RT_LIMIT_NET_ASYNC_QUEUE(default/max:64)AIC_RT_LIMIT_NET_ASYNC_WORKERS(default:1, max:32, clamped to the async op limit)AIC_RT_LIMIT_TLS_HANDLES(default/max:128)AIC_RT_LIMIT_TLS_ASYNC_OPS(default/max:256)AIC_RT_LIMIT_CONC_TASKS/AIC_RT_LIMIT_CONC_CHANNELS/AIC_RT_LIMIT_CONC_MUTEXES(default/max:128each)
tcp_recvand async recv wait paths returnNetError::ConnectionClosedon peer EOF/close.async_cancel_*keeps peer-close distinct by surfacingNetError::Cancelledon cancelled waits.dns_lookup_allreturns de-duplicated numeric addresses sorted lexicographically for deterministic failover iteration.- Windows
std.netservice-library contract:- Supported and CI-smoke-backed: TCP loopback (
tcp_listen,tcp_local_addr,tcp_connect,tcp_accept,tcp_send,tcp_recv,tcp_close) and async transport lifecycle (async_accept_submit,async_tcp_recv_submit,async_wait_*,async_cancel_*,async_shutdown) on the shared Windows backend. - Partial on Windows: UDP/DNS/socket tuning/shutdown/peer-address helpers are implemented in the shared runtime backend, but are not yet covered by Windows CI smoke; service libraries targeting Windows should keep typed fallbacks around those paths until broader validation lands.
- Unsupported socket-option/platform paths return
NetError::Iodeterministically; invalid-handle/type misuse remainsNetError::InvalidInput.
- Supported and CI-smoke-backed: TCP loopback (
tcp_send_timeoutandtcp_stream_send_timeoutenforce a total write timeout budget.tcp_stream_recv_exact*keeps reading untilexpected_bytesis satisfied or the deadline expires.tcp_stream_recv_framed*expects a 4-byte big-endian length prefix and enforcesmax_frame_bytes.tcp_set_nodelayandtcp_set_keepalivetoggle runtime socket flags and can be read back withtcp_get_*.tcp_set/get_keepalive_idle_secs,tcp_set/get_keepalive_interval_secs, andtcp_set/get_keepalive_counttune keepalive probe behavior where supported.- Fixed-width wrappers (
*_u32) are available for keepalive tunables and preserve deterministicInt <-> UInt32boundary checks. tcp_peer_addr/tcp_stream_peer_addrexpose remote endpoint identity for telemetry and policy checks.tcp_shutdown*/tcp_stream_shutdown*expose half-close/full-close controls for protocol flow control.tcp_set_send_buffer_sizeandtcp_set_recv_buffer_sizerequest kernel buffer sizes; read-back values may differ by platform/kernel.tcp_get_send_buffer_size_u32/tcp_get_recv_buffer_size_u32expose validated non-negative getter surfaces without changing runtimeIntintrinsics.- Async lifecycle control surface is protocol-neutral:
async_cancel_*returnsOk(true)when cancellation is applied andOk(false)when the op already completed.async_poll_*maps pending state toOk(None())via zero-timeout waits.async_wait_many_*returns the winning operation index and payload/value across arbitrary in-flight op sets.async_wait_any_*is a compatibility wrapper overasync_wait_many_*for two-op selection.async_runtime_pressureexposes active/queued snapshot metrics and configured limits for adaptive submit gating.- Net async pressure is aggregated across the worker pool;
queue_depth/queue_limitdescribe the shared submission queue, not a per-worker queue. - Phase-1 fixed-width wrappers expose non-negative domains via
UInt32(*_u32APIs) without breaking legacyIntsignatures.
- Recommended baseline for protocol clients: enable
tcp_set_nodelay(..., true)for request/response latency andtcp_set_keepalive(..., true)for pooled long-lived connections, then tune buffer sizes with measured traffic. - Tune keepalive probes with
tcp_set_keepalive_idle_secs,tcp_set_keepalive_interval_secs, andtcp_set_keepalive_countwhen idle-failure detection latency matters. - Capacity planning baseline: set
AIC_RT_LIMIT_NET_ASYNC_OPSto peak in-flight async ops per process, sizeAIC_RT_LIMIT_NET_ASYNC_QUEUEto absorb expected burst submissions, and raiseAIC_RT_LIMIT_NET_ASYNC_WORKERSabove1when service libraries need to spread async socket progress across multiple cores. - Failover baseline: call
dns_lookup_all(host)once per retry window, then iterate returned addresses in order while applying your per-attempt timeout budget. - For unsupported socket options/platforms, socket-tuning APIs return
NetError::Iodeterministically. - Invalid-handle/type socket-control calls remain typed (
NetError::InvalidInput), and shutdown on already-closed streams may surfaceNetError::ConnectionCloseddepending on platform socket state. - Port-domain policy for Wave 5A uses bounded unsigned ports (
UInt16) for typed parse/format wrappers while keeping existingaddr: Stringcompatibility signatures unchanged. - Wave 5C typed endpoint ABI contract:
- Runtime boundary is unchanged: lower-level net runtime and intrinsics continue to consume/produce
addr: Stringendpoints. - Typed wrappers are additive and deterministic (
NetPortU16,*_host_port,tcp_local_endpoint,net_format_host_port,net_parse_host_port). net_int_to_u16accepts only0..=65535; out-of-range values deterministically returnNetError::InvalidInput.net_parse_host_portparses exactly onehost:portboundary and rejects missing/extra separators withNetError::InvalidInput.net_format_host_portis canonical formatter behavior: decimal port, no hidden runtime-side widening/narrowing, no ABI field-layout changes.
- Runtime boundary is unchanged: lower-level net runtime and intrinsics continue to consume/produce
- Runnable lifecycle example:
examples/io/async_lifecycle_controls.aic. - Runnable worker-pool example:
examples/io/async_net_worker_pool.aic. - Runnable wait-many orchestration example:
examples/io/async_wait_many_orchestration.aic. - Adaptive pressure-gating example:
examples/io/async_runtime_pressure_gating.aic. - Typed endpoint migration example:
examples/data/net_typed_endpoint_u16.aic. - Scalar taxonomy artifact for prior wave baseline:
docs/io-fixed-width-taxonomy-wave2.md. - Wave 5A adoption matrix artifacts:
docs/numeric-api-adoption-wave5.mdanddocs/numeric-api-adoption-wave5.json.
enum TlsError {
HandshakeFailed,
CertificateInvalid,
CertificateExpired,
HostnameMismatch,
ProtocolError,
ConnectionClosed,
Cancelled,
Io,
Timeout,
}
struct TlsConfig {
verify_server: Bool,
ca_cert_path: Option[String],
client_cert_path: Option[String],
client_key_path: Option[String],
server_name: Option[String],
}
struct TlsStream {
handle: Int,
}
struct TlsAsyncIntSelection {
index: Int,
value: Int,
}
struct TlsAsyncStringSelection {
index: Int,
payload: Bytes,
}
struct TlsAsyncIntSelectionU32 {
index: UInt32,
value: UInt32,
}
struct TlsAsyncStringSelectionU32 {
index: UInt32,
payload: Bytes,
}
enum TlsVersion {
Tls12,
Tls13,
}
type TlsVersionCode = UInt8;
fn default_tls_config() -> TlsConfig
fn unsafe_insecure_tls_config(server_name: Option[String]) -> TlsConfig
fn tls_connect_with_config(tcp_fd: Int, config: TlsConfig) -> Result[TlsStream, TlsError] effects { net }
fn tls_connect(tcp_fd: Int, hostname: String, config: TlsConfig) -> Result[TlsStream, TlsError] effects { net }
fn tls_upgrade(tcp_fd: Int, hostname: String, config: TlsConfig) -> Result[TlsStream, TlsError] effects { net }
fn tls_connect_addr(addr: String, config: TlsConfig, timeout_ms: Int) -> Result[TlsStream, TlsError] effects { net }
fn tls_accept_timeout(listener_handle: Int, config: TlsConfig, timeout_ms: Int) -> Result[TlsStream, TlsError] effects { net }
fn tls_accept(listener_handle: Int, config: TlsConfig) -> Result[TlsStream, TlsError] effects { net }
fn tls_send(stream: TlsStream, payload: String) -> Result[Int, TlsError] effects { net }
fn tls_send_bytes(stream: TlsStream, data: Bytes) -> Result[Int, TlsError] effects { net }
fn tls_send_timeout(stream: TlsStream, payload: String, timeout_ms: Int) -> Result[Int, TlsError] effects { net }
fn tls_send_bytes_timeout(stream: TlsStream, data: Bytes, timeout_ms: Int) -> Result[Int, TlsError] effects { net }
fn tls_recv(stream: TlsStream, max_bytes: Int, timeout_ms: Int) -> Result[String, TlsError] effects { net }
fn tls_recv_u32(stream: TlsStream, max_bytes: UInt32, timeout_ms: Int) -> Result[String, TlsError] effects { net }
fn tls_recv_bytes(stream: TlsStream, max_bytes: Int, timeout_ms: Int) -> Result[Bytes, TlsError] effects { net }
fn tls_recv_bytes_u32(stream: TlsStream, max_bytes: UInt32, timeout_ms: Int) -> Result[Bytes, TlsError] effects { net }
fn tls_async_send_submit(stream: TlsStream, data: Bytes, timeout_ms: Int) -> Result[AsyncIntOp, TlsError] effects { net, concurrency }
fn tls_async_recv_submit(stream: TlsStream, max_bytes: Int, timeout_ms: Int) -> Result[AsyncStringOp, TlsError] effects { net, concurrency }
fn tls_async_recv_submit_u32(stream: TlsStream, max_bytes: UInt32, timeout_ms: Int) -> Result[AsyncStringOp, TlsError] effects { net, concurrency }
fn tls_async_wait_int(op: AsyncIntOp, timeout_ms: Int) -> Result[Int, TlsError] effects { net, concurrency }
fn tls_async_wait_string(op: AsyncStringOp, timeout_ms: Int) -> Result[Bytes, TlsError] effects { net, concurrency }
fn tls_async_cancel_int(op: AsyncIntOp) -> Result[Bool, TlsError] effects { net, concurrency }
fn tls_async_cancel_string(op: AsyncStringOp) -> Result[Bool, TlsError] effects { net, concurrency }
fn tls_async_poll_int(op: AsyncIntOp) -> Result[Option[Int], TlsError] effects { net, concurrency }
fn tls_async_poll_string(op: AsyncStringOp) -> Result[Option[Bytes], TlsError] effects { net, concurrency }
fn tls_async_wait_many_int(ops: Vec[AsyncIntOp], timeout_ms: Int) -> Result[TlsAsyncIntSelection, TlsError] effects { net, concurrency, time }
fn tls_async_wait_many_int_u32(ops: Vec[AsyncIntOp], timeout_ms: Int) -> Result[TlsAsyncIntSelectionU32, TlsError] effects { net, concurrency, time }
fn tls_async_wait_many_string(ops: Vec[AsyncStringOp], timeout_ms: Int) -> Result[TlsAsyncStringSelection, TlsError] effects { net, concurrency, time }
fn tls_async_wait_many_string_u32(ops: Vec[AsyncStringOp], timeout_ms: Int) -> Result[TlsAsyncStringSelectionU32, TlsError] effects { net, concurrency, time }
fn tls_async_wait_any_int(op1: AsyncIntOp, op2: AsyncIntOp, timeout_ms: Int) -> Result[TlsAsyncIntSelection, TlsError] effects { net, concurrency, time }
fn tls_async_wait_any_int_u32(op1: AsyncIntOp, op2: AsyncIntOp, timeout_ms: Int) -> Result[TlsAsyncIntSelectionU32, TlsError] effects { net, concurrency, time }
fn tls_async_wait_any_string(op1: AsyncStringOp, op2: AsyncStringOp, timeout_ms: Int) -> Result[TlsAsyncStringSelection, TlsError] effects { net, concurrency, time }
fn tls_async_wait_any_string_u32(op1: AsyncStringOp, op2: AsyncStringOp, timeout_ms: Int) -> Result[TlsAsyncStringSelectionU32, TlsError] effects { net, concurrency, time }
fn tls_async_runtime_pressure() -> Result[AsyncRuntimePressure, TlsError] effects { net, concurrency }
fn tls_async_runtime_pressure_u32() -> Result[AsyncRuntimePressureU32, TlsError] effects { net, concurrency }
fn tls_async_send(stream: TlsStream, data: Bytes, timeout_ms: Int) -> Result[Int, TlsError] effects { net, concurrency }
fn tls_async_recv(stream: TlsStream, max_bytes: Int, timeout_ms: Int) -> Result[Bytes, TlsError] effects { net, concurrency }
fn tls_async_recv_u32(stream: TlsStream, max_bytes: UInt32, timeout_ms: Int) -> Result[Bytes, TlsError] effects { net, concurrency }
fn tls_async_shutdown() -> Result[Bool, TlsError] effects { net, concurrency }
fn tls_frame_len_be_u32(header: Bytes) -> Result[UInt32, TlsError]
fn tls_recv_exact_deadline(stream: TlsStream, expected_bytes: Int, deadline_ms: Int) -> Result[Bytes, TlsError] effects { net, time }
fn tls_recv_exact_deadline_u32(stream: TlsStream, expected_bytes: UInt32, deadline_ms: Int) -> Result[Bytes, TlsError] effects { net, time }
fn tls_recv_exact(stream: TlsStream, expected_bytes: Int, timeout_ms: Int) -> Result[Bytes, TlsError] effects { net, time }
fn tls_recv_exact_u32(stream: TlsStream, expected_bytes: UInt32, timeout_ms: Int) -> Result[Bytes, TlsError] effects { net, time }
fn tls_recv_framed_deadline(stream: TlsStream, max_frame_bytes: Int, deadline_ms: Int) -> Result[Bytes, TlsError] effects { net, time }
fn tls_recv_framed_deadline_u32(stream: TlsStream, max_frame_bytes: UInt32, deadline_ms: Int) -> Result[Bytes, TlsError] effects { net, time }
fn tls_recv_framed(stream: TlsStream, max_frame_bytes: Int, timeout_ms: Int) -> Result[Bytes, TlsError] effects { net, time }
fn tls_recv_framed_u32(stream: TlsStream, max_frame_bytes: UInt32, timeout_ms: Int) -> Result[Bytes, TlsError] effects { net, time }
fn tls_close(stream: TlsStream) -> Result[Bool, TlsError] effects { net }
fn byte_stream_recv(stream: ByteStream, max_bytes: Int, timeout_ms: Int) -> Result[Bytes, ByteStreamError] effects { net }
fn byte_stream_recv_u32(stream: ByteStream, max_bytes: UInt32, timeout_ms: Int) -> Result[Bytes, ByteStreamError] effects { net }
fn byte_stream_recv_exact_deadline(stream: ByteStream, expected_bytes: Int, deadline_ms: Int) -> Result[Bytes, ByteStreamError] effects { net, time }
fn byte_stream_recv_exact_deadline_u32(stream: ByteStream, expected_bytes: UInt32, deadline_ms: Int) -> Result[Bytes, ByteStreamError] effects { net, time }
fn byte_stream_recv_exact(stream: ByteStream, expected_bytes: Int, timeout_ms: Int) -> Result[Bytes, ByteStreamError] effects { net, time }
fn byte_stream_recv_exact_u32(stream: ByteStream, expected_bytes: UInt32, timeout_ms: Int) -> Result[Bytes, ByteStreamError] effects { net, time }
fn byte_stream_recv_framed_deadline(stream: ByteStream, max_frame_bytes: Int, deadline_ms: Int) -> Result[Bytes, ByteStreamError] effects { net, time }
fn byte_stream_recv_framed_deadline_u32(stream: ByteStream, max_frame_bytes: UInt32, deadline_ms: Int) -> Result[Bytes, ByteStreamError] effects { net, time }
fn byte_stream_recv_framed(stream: ByteStream, max_frame_bytes: Int, timeout_ms: Int) -> Result[Bytes, ByteStreamError] effects { net, time }
fn byte_stream_recv_framed_u32(stream: ByteStream, max_frame_bytes: UInt32, timeout_ms: Int) -> Result[Bytes, ByteStreamError] effects { net, time }
fn byte_stream_send_timeout(stream: ByteStream, payload: Bytes, timeout_ms: Int) -> Result[Int, ByteStreamError] effects { net }
fn tls_peer_subject(stream: TlsStream) -> Result[String, TlsError] effects { net }
fn tls_peer_issuer(stream: TlsStream) -> Result[String, TlsError] effects { net }
fn tls_peer_fingerprint_sha256(stream: TlsStream) -> Result[String, TlsError] effects { net }
fn tls_peer_san_entries(stream: TlsStream) -> Result[Vec[String], TlsError] effects { net }
fn tls_peer_cn(stream: TlsStream) -> Result[String, TlsError] effects { net }
fn tls_version_to_code(version: TlsVersion) -> TlsVersionCode
fn tls_version_from_code(code: TlsVersionCode) -> Result[TlsVersion, TlsError]
fn tls_version_code(stream: TlsStream) -> Result[TlsVersionCode, TlsError] effects { net }
fn tls_version(stream: TlsStream) -> Result[TlsVersion, TlsError] effects { net }
Notes:
default_tls_config()is secure-by-default (verify_server: true).unsafe_insecure_tls_config(...)is the explicit unsafe override path (verify_server: false).- Unsafe override emits runtime audit warning tag:
AIC_TLS_POLICY_UNSAFE. - Machine-readable policy contract:
docs/security-ops/tls-policy.v1.json. tls_connect_with_configupgrades an existing TCP connection handle usingconfig.server_namewhen provided.tls_connect/tls_upgradeare explicit hostname-aware wrappers for StartTLS-style upgrades over existing TCP handles.tls_connect_addrperforms TCP connect + TLS handshake in one call.tls_accept/tls_accept_timeoutprovide server-side TLS wrapping over listener handles.tls_send_bytes/tls_recv_bytesare the stable binary payload APIs for protocol clients.tls_send_timeout/tls_send_bytes_timeoutprovide timeout-bounded TLS write APIs.- TLS async submit/wait APIs are bytes-first and typed:
tls_async_send_submit/tls_async_recv_submittls_async_wait_int/tls_async_wait_stringtls_async_cancel_*/tls_async_poll_*/tls_async_wait_many_*tls_async_wait_any_*compatibility wrappers overtls_async_wait_many_*for two-op selectiontls_async_runtime_pressurefor slot-backed runtime capacity snapshots (queue_depthmirrors occupied TLS async slots andqueue_limitmirrors the configured TLS async slot limit)- convenience wrappers
tls_async_send/tls_async_recv - phase-1 fixed-width wrappers (
*_u32) for byte-count, frame-length, selection-index, and pressure-counter domains.
byte_stream_send_timeoutapplies timeout-bounded writes across TCP and TLS streams.tls_recv/tls_recv_bytesreturnTlsError::ConnectionClosedon peer EOF/close while timeout remains non-close (TlsError::Timeout).tls_send_timeoutdeadline expiry maps toTlsError::Timeout.tls_async_wait_*timeout returnsTlsError::Timeoutand keeps the op pending so a later wait can retry.tls_async_cancel_*marks pending ops as cancelled and surfacesTlsError::Cancelledfrom subsequent waits.- Re-waiting a consumed TLS async op returns
TlsError::ProtocolError. - Runnable async TLS submit/wait example:
examples/io/tls_async_submit_wait.aic. - TLS peer metadata APIs (
tls_peer_subject,tls_peer_issuer,tls_peer_fingerprint_sha256,tls_peer_san_entries) expose generic inputs for external pinning/compliance policies. tls_peer_san_entriesreturns an empty vector when SAN is absent while unsupported metadata paths map toTlsError::ProtocolError.- Generic TLS metadata pinning scaffold example:
examples/io/tls_metadata_pinning_scaffold.aic. tls_recv_exact*andbyte_stream_recv_exact*are deadline-based exact byte readers.tls_recv_framed*andbyte_stream_recv_framed*decode a 4-byte big-endian length prefix and enforce frame-size bounds.tls_version_codereports bounded negotiated protocol codes (12or13) andtls_versionremains the compatibility enum wrapper (Tls12orTls13).tls_peer_cnextracts the peer certificate common name from the subject string.- Canonical deterministic Postgres-style secure client replay:
examples/io/postgres_tls_scram_reference.aic. - Replay contract:
docs/security-ops/postgres-tls-scram-replay.v1.json. - On platforms without TLS backend support, APIs return
TlsError::ProtocolError. - Scalar taxonomy artifact for prior wave baseline:
docs/io-fixed-width-taxonomy-wave2.md. - Wave 5A adoption matrix artifacts:
docs/numeric-api-adoption-wave5.mdanddocs/numeric-api-adoption-wave5.json.
struct SecureErrorInfo {
module_name: String,
code: String,
category: String,
retryable: Bool,
}
enum PoolErrorContract {
MaxSizeReached,
Timeout,
ConnectionFailed,
Closed,
HealthCheckFailed,
}
fn buffer_error_info(err: BufferError) -> SecureErrorInfo
fn crypto_error_info(err: CryptoError) -> SecureErrorInfo
fn tls_error_info(err: TlsError) -> SecureErrorInfo
fn pool_error_info(err: PoolErrorContract) -> SecureErrorInfo
Notes:
- Canonical machine-readable contract:
docs/errors/secure-networking-error-contract.v1.json. - Existing error
codevalues,category, andretryableflags are compatibility-stable. - Contract is additive-only for future changes.
enum TimeError {
InvalidFormat,
InvalidDate,
InvalidTime,
InvalidOffset,
InvalidInput,
Internal,
}
struct DateTime {
year: Int,
month: Int,
day: Int,
hour: Int,
minute: Int,
second: Int,
millisecond: Int,
offset_minutes: Int,
}
fn now_ms() -> Int effects { time }
fn now() -> Int effects { time }
fn monotonic_ms() -> Int effects { time }
fn sleep_ms(ms: Int) -> () effects { time }
fn parse_rfc3339(text: String) -> Result[DateTime, TimeError] effects { time }
fn parse_iso8601(text: String) -> Result[DateTime, TimeError] effects { time }
fn format_rfc3339(value: DateTime) -> Result[String, TimeError] effects { time }
fn format_iso8601(value: DateTime) -> Result[String, TimeError] effects { time }
fn deadline_after_ms(timeout_ms: Int) -> Int effects { time }
fn remaining_ms(deadline_ms: Int) -> Int effects { time }
fn timeout_expired(deadline_ms: Int) -> Bool effects { time }
fn sleep_until(deadline_ms: Int) -> () effects { time }
Notes:
now()is compatibility API and is deprecated in policy metadata in favor ofnow_ms().parse_rfc3339requires timezone and seconds.parse_iso8601accepts date-only and timezone-optional forms.
fn seed(seed_value: Int) -> () effects { rand }
fn random_int() -> Int effects { rand }
fn random_bool() -> Bool effects { rand }
fn random_range(min_inclusive: Int, max_exclusive: Int) -> Int effects { rand }
Notes:
seed(...)makes sequences deterministic.random_range(a, b)returnsawhenb <= a.
struct RetryConfig {
max_attempts: Int,
initial_backoff_ms: Int,
backoff_multiplier: Int,
max_backoff_ms: Int,
jitter_enabled: Bool,
jitter_ms: Int,
}
struct RetryResult[T] {
result: Result[T, String],
attempts: Int,
elapsed_ms: Int,
}
fn default_retry_config() -> RetryConfig
fn retry[T](config: RetryConfig, operation: Fn() -> Result[T, String]) -> RetryResult[T] effects { time, rand }
fn with_timeout[T](timeout_ms: Int, operation: Fn() -> T) -> Result[T, String] effects { time }
Notes:
retryuses exponential backoff (initial_backoff_ms,backoff_multiplier) capped bymax_backoff_ms.- Jitter is optional and controlled by
jitter_enabled+jitter_ms. RetryResultalways reportsattemptsand totalelapsed_ms.with_timeoutenforces deadline checks before and after operation execution; the wrapped operation is not force-cancelled mid-call.- Secure pooled retry reference (including timeout/capacity negatives):
examples/io/postgres_tls_scram_reference.aic.
enum PoolError {
MaxSizeReached,
Timeout,
ConnectionFailed,
Closed,
HealthCheckFailed,
}
struct PoolConfig {
min_size: Int,
max_size: Int,
acquire_timeout_ms: Int,
idle_timeout_ms: Int,
max_lifetime_ms: Int,
health_check_ms: Int,
}
struct Pool[T] {
handle: Int,
}
struct PooledConn[T] {
handle: Int,
value: T,
}
struct PoolStats {
total: Int,
idle: Int,
in_use: Int,
created: Int,
destroyed: Int,
}
fn new_pool[T](
config: PoolConfig,
create: Fn() -> Result[T, PoolError],
health_check: Fn(T) -> Bool,
destroy: Fn(T) -> (),
) -> Result[Pool[T], PoolError] effects { concurrency }
fn acquire[T](pool: Pool[T]) -> Result[PooledConn[T], PoolError] effects { concurrency }
fn release[T](conn: PooledConn[T]) -> () effects { concurrency }
fn discard[T](conn: PooledConn[T]) -> () effects { concurrency }
fn pool_stats[T](pool: Pool[T]) -> PoolStats effects { concurrency }
fn close_pool[T](pool: Pool[T]) -> () effects { concurrency }
Notes:
- Use typed callback bindings (
Fn() -> Result[Conn, PoolError], etc.) and a typedpool_result: Result[Pool[Conn], PoolError]binding for stable inference. discard(...)is for broken resources; it destroys and rotates capacity.pool_stats(...)is safe for runtime observability and CI assertions.- Runnable reference:
examples/io/connection_pool.aic.
enum BufferError {
Underflow,
Overflow,
InvalidUtf8,
InvalidInput,
}
struct ByteBuffer {
handle: Int,
}
type BufferCapacityU32 = UInt32
type BufferOffsetU32 = UInt32
type BufferCountU32 = UInt32
fn new_buffer(capacity: Int) -> ByteBuffer
fn new_buffer_u32(capacity: BufferCapacityU32) -> Result[ByteBuffer, BufferError]
fn new_growable_buffer(initial_capacity: Int, max_capacity: Int) -> Result[ByteBuffer, BufferError]
fn new_growable_buffer_u32(initial_capacity: BufferCapacityU32, max_capacity: BufferCapacityU32) -> Result[ByteBuffer, BufferError]
fn buffer_from_bytes(data: Bytes) -> ByteBuffer
fn buffer_to_bytes(buf: ByteBuffer) -> Bytes
fn buf_position(buf: ByteBuffer) -> Int
fn buf_remaining(buf: ByteBuffer) -> Int
fn buf_position_u32(buf: ByteBuffer) -> Result[BufferOffsetU32, BufferError]
fn buf_remaining_u32(buf: ByteBuffer) -> Result[BufferCountU32, BufferError]
fn buf_size(buf: ByteBuffer) -> Int
fn buf_size_u32(buf: ByteBuffer) -> Result[BufferCountU32, BufferError]
fn buf_seek(buf: ByteBuffer, position: Int) -> Result[(), BufferError]
fn buf_seek_u32(buf: ByteBuffer, position: BufferOffsetU32) -> Result[(), BufferError]
fn buf_reset(buf: ByteBuffer) -> ()
fn buf_close(buf: ByteBuffer) -> Result[Bool, BufferError]
fn buf_peek_u8(buf: ByteBuffer, position: Int) -> Result[UInt8, BufferError]
fn buf_slice(buf: ByteBuffer, start: Int, length: Int) -> Result[ByteBuffer, BufferError]
fn buf_slice_u32(buf: ByteBuffer, start: BufferOffsetU32, length: BufferCountU32) -> Result[ByteBuffer, BufferError]
fn buf_read_u8(buf: ByteBuffer) -> Result[UInt8, BufferError]
fn buf_read_i16_be(buf: ByteBuffer) -> Result[Int16, BufferError]
fn buf_read_u16_be(buf: ByteBuffer) -> Result[UInt16, BufferError]
fn buf_read_i32_be(buf: ByteBuffer) -> Result[Int32, BufferError]
fn buf_read_u32_be(buf: ByteBuffer) -> Result[UInt32, BufferError]
fn buf_read_i64_be(buf: ByteBuffer) -> Result[Int64, BufferError]
fn buf_read_u64_be(buf: ByteBuffer) -> Result[UInt64, BufferError]
fn buf_read_i16_le(buf: ByteBuffer) -> Result[Int16, BufferError]
fn buf_read_u16_le(buf: ByteBuffer) -> Result[UInt16, BufferError]
fn buf_read_i32_le(buf: ByteBuffer) -> Result[Int32, BufferError]
fn buf_read_u32_le(buf: ByteBuffer) -> Result[UInt32, BufferError]
fn buf_read_i64_le(buf: ByteBuffer) -> Result[Int64, BufferError]
fn buf_read_u64_le(buf: ByteBuffer) -> Result[UInt64, BufferError]
fn buf_read_bytes(buf: ByteBuffer, count: Int) -> Result[Bytes, BufferError]
fn buf_read_bytes_u32(buf: ByteBuffer, count: BufferCountU32) -> Result[Bytes, BufferError]
fn buf_read_cstring(buf: ByteBuffer) -> Result[String, BufferError]
fn buf_read_length_prefixed(buf: ByteBuffer) -> Result[Bytes, BufferError]
fn buf_write_u8(buf: ByteBuffer, value: UInt8) -> Result[(), BufferError]
fn buf_write_i16_be(buf: ByteBuffer, value: Int16) -> Result[(), BufferError]
fn buf_write_u16_be(buf: ByteBuffer, value: UInt16) -> Result[(), BufferError]
fn buf_write_i32_be(buf: ByteBuffer, value: Int32) -> Result[(), BufferError]
fn buf_write_u32_be(buf: ByteBuffer, value: UInt32) -> Result[(), BufferError]
fn buf_write_i64_be(buf: ByteBuffer, value: Int64) -> Result[(), BufferError]
fn buf_write_u64_be(buf: ByteBuffer, value: UInt64) -> Result[(), BufferError]
fn buf_write_i16_le(buf: ByteBuffer, value: Int16) -> Result[(), BufferError]
fn buf_write_u16_le(buf: ByteBuffer, value: UInt16) -> Result[(), BufferError]
fn buf_write_i32_le(buf: ByteBuffer, value: Int32) -> Result[(), BufferError]
fn buf_write_u32_le(buf: ByteBuffer, value: UInt32) -> Result[(), BufferError]
fn buf_write_i64_le(buf: ByteBuffer, value: Int64) -> Result[(), BufferError]
fn buf_write_u64_le(buf: ByteBuffer, value: UInt64) -> Result[(), BufferError]
fn buf_write_bytes(buf: ByteBuffer, data: Bytes) -> Result[(), BufferError]
fn buf_write_cstring(buf: ByteBuffer, s: String) -> Result[(), BufferError]
fn buf_write_string_prefixed(buf: ByteBuffer, s: String) -> Result[(), BufferError]
fn buf_patch_u16_be(buf: ByteBuffer, offset: Int, value: UInt16) -> Result[(), BufferError]
fn buf_patch_u32_be(buf: ByteBuffer, offset: Int, value: UInt32) -> Result[(), BufferError]
fn buf_patch_u64_be(buf: ByteBuffer, offset: Int, value: UInt64) -> Result[(), BufferError]
fn buf_patch_u16_le(buf: ByteBuffer, offset: Int, value: UInt16) -> Result[(), BufferError]
fn buf_patch_u32_le(buf: ByteBuffer, offset: Int, value: UInt32) -> Result[(), BufferError]
fn buf_patch_u64_le(buf: ByteBuffer, offset: Int, value: UInt64) -> Result[(), BufferError]
Notes:
- APIs are pure (no effect declaration required).
new_buffer(capacity)is fixed-capacity; writes past capacity returnOverflow.new_growable_buffer(initial_capacity, max_capacity)grows automatically up tomax_capacity; writes beyond that cap returnOverflow.- Legacy
Intsignatures remain compatibility surfaces; additive_u32wrappers delegate to the same runtime intrinsics. - Reads past available bytes return
Underflow(never panic). buf_read_cstringrequires null-terminated valid UTF-8; invalid payload returnsInvalidUtf8.buf_read_length_prefixedexpects signed big-endian i32 length; negative lengths returnInvalidInput.buf_seekvalidates bounds (0 <= position <= length) and returnsInvalidInputon invalid positions.- Conversion boundary policy for
_u32wrappers is deterministic:Int -> UInt32wrapper paths reject negative or >4294967295values withInvalidInput.UInt32 -> Intwrapper paths reject values above runtimeIntcompatibility ceiling (2147483647) withInvalidInput.
buf_closereleases buffer storage explicitly; drop cleanup is idempotent and safe after explicit close.- unsigned reads/writes (
u16/u32/u64) use typedUInt16/UInt32/UInt64signatures, and signed variants useInt16/Int32/Int64. - For explicit unsigned frame-length reads, prefer
buf_read_u32_be+buf_read_bytes_u32;buf_read_length_prefixedstays as a signed-compatibility entrypoint. - Frame-length policy for Wave 5A treats protocol length prefixes as unsigned (
UInt32) and tracks compatibility wrappers indocs/numeric-api-adoption-wave5.md(rowP1). - patch helpers (
buf_patch_u*_be/le) seek-write-restore the cursor for deterministic backfill fields. buf_peek_u8reads at absolute position without changing cursor state.buf_sizereturns total bytes currently stored in the buffer.buf_slicereturns aByteBufferfor a validated sub-range (start,length) using byte-level slicing.
enum CryptoError {
InvalidInput,
UnsupportedAlgorithm,
Internal,
}
fn md5(data: String) -> String
fn md5_bytes(data: Bytes) -> String
fn sha256(data: String) -> String
fn sha256_raw(data: String) -> Bytes
fn hmac_sha256(key: String, message: String) -> String
fn hmac_sha256_raw(key: Bytes, message: Bytes) -> Bytes
fn pbkdf2_sha256(password: String, salt: Bytes, iterations: Int, key_length: Int) -> Result[Bytes, CryptoError]
fn hex_encode(data: Bytes) -> String
fn hex_decode(hex: String) -> Result[Bytes, CryptoError]
fn base64_encode(data: Bytes) -> String
fn base64_decode(b64: String) -> Result[Bytes, CryptoError]
fn random_bytes(count: Int) -> Bytes effects { rand }
fn secure_eq(a: Bytes, b: Bytes) -> Bool
Notes:
- Hash/HMAC/encode/decode functions are pure and deterministic.
random_bytesis the onlystd.cryptoAPI requiringeffects { rand }.secure_eqis byte-oriented and intended for secret comparisons.hex_decode,base64_decode, andpbkdf2_sha256return typedCryptoErrorvariants instead of panicking.- Reference flow for Postgres MD5 + SCRAM derivations:
examples/crypto/pg_scram_auth.aic. - End-to-end secure replay template:
examples/io/postgres_tls_scram_reference.aic.
cargo run --quiet --bin aic -- std-compat
cargo run --quiet --bin aic -- check examples/io/interactive_greeter.aic
cargo run --quiet --bin aic -- check examples/io/tls_connect.aic
cargo run --quiet --bin aic -- check examples/io/postgres_tls_scram_reference.aic
cargo run --quiet --bin aic -- run examples/io/postgres_tls_scram_reference.aic
cargo run --quiet --bin aic -- check examples/data/wave5_migration_buffer_u32.aic
cargo run --quiet --bin aic -- run examples/data/wave5_migration_buffer_u32.aic
cargo run --quiet --bin aic -- check examples/data/wave5_numeric_end_to_end.aic
cargo run --quiet --bin aic -- run examples/data/wave5_numeric_end_to_end.aic
cargo test --locked --test unit_tests unit_wave5d_docs_examples_and_command_policy_markers_are_present
cargo test --locked --test agent_recipe_tests wave5d_numeric_docs_examples_and_ci_policy_are_consistent
cargo run --quiet --bin aic -- explain E2001