Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

50 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

A3S Runtime

Provider-Neutral Task and Service Runtime for A3S

Converge immutable workload generations across local, container, sandbox, and remote execution providers

OverviewFeaturesRuntime ModelOperationsDurable StateProvidersConformanceDevelopment


Overview

A3S Runtime defines a general execution contract for finite Tasks and long-running Services. A caller submits an immutable unit generation, a provider materializes it, and observations show whether provider state has converged with the requested specification.

Runtime owns provider-neutral lifecycle semantics, capability discovery, durable unit identity, and idempotent request handling. Scheduling, deployment workflows, routing, product profiles, and provider-selection policy remain in their owning applications.

Features

  • One General Unit Model: Run finite Tasks and long-running Services through the same client and provider interface
  • Immutable Generations: Bind every operation and observation to a unit ID, positive generation, and canonical specification digest
  • Idempotent Lifecycle: Apply, inspect, stop, and remove units with durable request receipts and deterministic conflict detection
  • Structured Capabilities: Match artifact, isolation, network, mount, health, resource, and optional feature requirements before provider dispatch
  • Provider-Neutral Inputs: Describe processes, artifacts, mounts, secret references, resources, networking, health checks, restart policy, and outputs
  • Observed Convergence: Keep desired specifications separate from provider observations, usage, evidence, output artifacts, and failure details
  • Durable Local State: Persist owner-only records atomically under cross-process locks without following symbolic-link state boundaries
  • Logs and Exec: Expose generation-bound log and exec surfaces only when a provider reports the corresponding capability, with typed cursor-loss and source-disconnect discontinuities
  • Capability-Driven Conformance: Always run complete Base and Recovery profiles, automatically activate advertised optional profiles, and reject missing fixtures, incomplete evidence, or provider inventory leaks

Runtime Model

Unit classes

Class Lifecycle Typical work
Task Finite; converges at succeeded Build, migration, evaluation, backup
Service Long-running; converges at running and healthy when configured Application, Agent, MCP server

RuntimeUnitSpec is immutable for a (unit_id, generation) pair. Changing any field requires the next generation. Reusing a generation with different content fails with GenerationConflict; submitting an older generation fails with StaleGeneration.

Specification

A unit specification includes:

  • a digest-bound artifact reference and media type;
  • command, arguments, working directory, and environment;
  • artifact, volume, and temporary-filesystem mounts;
  • provider-resolved secret references and delivery targets;
  • network mode, named ports, and transport protocols;
  • CPU, memory, process, ephemeral-storage, and optional execution limits;
  • isolation level, health probe, restart policy, and Task outputs;
  • an optional digest binding caller-owned execution semantics.

All wire records use explicit schema identifiers and reject unknown fields. RuntimeUnitSpec v2 makes the ephemeral-storage quota optional; a provider needs that resource control only when a specification requests the quota. Protocol validation occurs before state reservation or provider work.

Observations

RuntimeObservation binds provider state to the exact unit ID, generation, class, and specification digest. It can carry stable provider identity, health, resource usage, output artifacts, evidence, attestation, and structured failure.

Terminal observations are immutable. If a previously observed provider resource cannot be found, inspection records unknown; it does not silently report success or erase the last provider identity.

Operations

The RuntimeClient contract exposes:

Operation Semantics
capabilities Return and validate the provider's structured capabilities
apply Create, reattach, or converge one immutable unit generation
inspect Return the latest observation or a generation-aware absence
stop Stop the active generation without deleting durable identity
remove Remove the provider resource and persist an absence tombstone
logs Read strictly ordered, cursor-addressed log chunks or return a typed permanent discontinuity
exec Execute one bounded, buffered command against the exact active generation

Each mutating request carries its own request ID and optional absolute deadline. An exact retry returns or reconstructs the same logical result. Reusing a request ID with different content fails with RequestConflict. A completed receipt remains replayable after its original deadline and after later lifecycle operations; an expired pending request is not redispatched. A deadline is checked independently before new provider work. On the first exec reservation, Runtime persists the smaller of started_at + timeout_ms and the optional caller deadline. RuntimeDriver::exec receives that effective absolute deadline in deadline_at_ms, and every pending replay receives the same value, so retrying cannot restart or extend the execution window.

exec is a unary, non-interactive operation. Its single result contains an exit code, separate buffered stdout and stderr of at most 16 MiB each, and a truncation indicator. RuntimeFeature::Exec does not advertise stdin, PTY, terminal resize, signals, incremental output, or reconnectable sessions. Interactive streaming must not be emulated with log cursors or repeated unary requests.

Log transport or provider availability failures remain retryable errors. A provider that can prove the requested cursor was lost, or that the durable unit survives after its log source disappeared, instead returns RuntimeError::LogDiscontinuity with the exact unit, generation, requested cursor, and typed reason. Callers can durably project that boundary before resuming from the earliest currently available record without parsing error text.

Capabilities

Providers report supported unit classes, artifact media types, isolation levels, network modes, mount kinds, health probes, resource controls, and optional features. ManagedRuntimeClient validates the complete specification against those capabilities before reserving state, so unsupported work cannot leave a pending record or partially created provider resource.

The registry maps explicit ProviderId values to typed factories. It does not choose a provider, infer login state, or fall back to a default. Callers own that policy and pass the selected ID to RuntimeClientRegistry::connect.

Durable State

FileRuntimeStateStore provides the local durable boundary for a managed provider integration:

state root/
├── locks/                   # short per-unit record locks
├── operations/              # full-operation cross-process leases
└── units/
    └── <unit-key>/
        ├── record.json      # active unit record
        └── requests/        # one durable receipt per request ID

The store uses a SHA-256 storage key derived from the validated unit ID. Records are written through an owner-only temporary file, synchronized, atomically published, and followed by a directory sync. State directories, lock files, and records reject symbolic-link boundaries; Unix permissions are tightened to 0700 for directories and 0600 for files.

Pending receipts deliberately survive ambiguous transport failures. Retrying the same apply request dispatches the same durable unit identity so an idempotent provider driver can discover or converge the existing resource.

Provider Integration

A provider implements RuntimeDriver and reports a stable ProviderId through a RuntimeProviderFactory. The driver receives validated specifications and durable unit records; it never owns request conflict or generation policy.

ManagedRuntimeClient composes three replaceable boundaries:

RuntimeClient
    |
    v
ManagedRuntimeClient
    ├── RuntimeStateStore   durable identities and receipts
    ├── RuntimeDriver       provider resource lifecycle
    └── RuntimeClock        deadline and observation time source

Provider apply must be idempotent for the supplied unit ID and generation. After an ambiguous acknowledgement, a repeated call must discover or converge the same resource rather than create another one. A successful generation handoff must retire all older provider generations and verify that exactly the current resource remains; interrupted handoffs finish on exact retry. Provider-specific labels, SDK handles, container fields, and transport details stay behind the driver.

Conformance

Production provider repositories should implement RuntimeConformanceFixture and run verify_runtime_profiles against real, disposable infrastructure:

use a3s_runtime::{verify_runtime_profiles, RuntimeConformanceFixture};

let fixture: &dyn RuntimeConformanceFixture = provider_fixture;
let report = verify_runtime_profiles(client.as_ref(), fixture).await?;
assert_eq!(report.inventory_before, report.inventory_after);

The mandatory Base profile covers successful, failed, and timed-out Tasks; Service apply, inspect, stop, and removal; exact replay; generation conflicts; and tombstones. Recovery is mandatory for every production provider. Networking, Mounts, Health, Resources, Logs, Exec, Security, Outputs, and Evidence activate from reported capabilities. A fixture must return the shared stable case IDs and capability claims for every activated profile, perform cleanup even after a failed profile, and prove that its canonical provider inventory returned to the pre-run baseline.

Profile requirements expand to one case ID per advertised behavior rather than accepting a generic family-level claim. For example, every reported network mode, mount kind, health probe, and resource control activates its own configuration and behavioral cases. NetworkMode::Service activates both TCP and UDP because the current protocol has no narrower transport-protocol capability. Logs separately require filtering, total order, cursor resume, same-timestamp handling, limits, explicit rotation gaps, terminal retention, and bounded large records.

verify_runtime_provider remains available as the lower-level successful Task and Service lifecycle check. It is not, by itself, production certification. Provider-specific fixtures still own real daemon restart, external deletion, security, resource-behavior, and destructive cleanup mechanics; the shared harness owns activation, required case/claim coverage, Base semantics, and the zero-inventory-delta oracle.

See the deep test plan for the full contract, durability, real-provider, fault, performance, soak, and A3S OS release gates.

Architecture

The contract and managed lifecycle are intentionally independent of product and provider concerns:

caller policy and workflow
          |
          v
provider-neutral Runtime contract
          |
          v
managed durability and validation
          |
          v
provider driver and external runtime

See ADR 0001 for the general ownership model, ADR 0002 for the completed protocol and operation semantics, ADR 0003 for the bounded unary exec boundary, and the implementation plan for the dependency-ordered delivery tasks.

Development

Run validation from this crate repository, not from the A3S monorepo root:

cargo fmt --all --check
cargo test --all-targets
cargo clippy --all-targets -- -D warnings
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps

The integration suite covers Task and Service behavior, request and generation conflicts, ambiguous retry, capability rejection, provider identity, generation-bound logs and exec, independent deadlines, provider disappearance, terminal immutability, concurrent file reservations, symbolic-link rejection, registry behavior, and the exported provider conformance path.

About

Task and Service Runtime

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages