From 31b505294451b0a3d17984e9b5c43d105955d472 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 26 Jul 2026 16:07:38 +0100 Subject: [PATCH 01/14] chore: update guix.scm from squisher-corpus --- guix.scm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/guix.scm b/guix.scm index 83e4fe8..c6dd7be 100644 --- a/guix.scm +++ b/guix.scm @@ -1,5 +1,5 @@ ; SPDX-License-Identifier: MPL-2.0 -;; guix.scm — GNU Guix package definition for AcceleratorGate.jl +;; guix.scm — GNU Guix package definition for squisher-corpus ;; Usage: guix shell -f guix.scm (use-modules (guix packages) @@ -7,12 +7,12 @@ (guix licenses)) (package - (name "AcceleratorGate.jl") + (name "squisher-corpus") (version "0.1.0") (source #f) (build-system gnu-build-system) - (synopsis "AcceleratorGate.jl") - (description "AcceleratorGate.jl — part of the hyperpolymath ecosystem.") - (home-page "https://github.com/hyperpolymath/AcceleratorGate.jl") - (license ((@@ (guix licenses) license) "MPL-2.0" - "https://www.mozilla.org/MPL/2.0/"))) + (synopsis "squisher-corpus") + (description "squisher-corpus — part of the hyperpolymath ecosystem.") + (home-page "https://github.com/hyperpolymath/squisher-corpus") + (license ((@@ (guix licenses) license) "PMPL-1.0-or-later" + "https://github.com/hyperpolymath/palimpsest-license"))) From 6f30c8d9014cb719ec754a54860684b0309e6ec7 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 3 Aug 2026 13:55:22 +0100 Subject: [PATCH 02/14] =?UTF-8?q?fix(ci):=20repair=20parse-dead=20workflow?= =?UTF-8?q?=20=E2=80=94=20K9-SVC=20step=20at=20job-level=20indent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A sweep appended a `K9-SVC Validation` step at two-space indentation — the level of a job key under `jobs:` — instead of the six spaces that would place it inside a job's `steps:` list. YAML then hits a sequence item where it expects a block mapping, and the whole file fails to parse. Actions rejects a workflow that does not parse *before* allocating a runner, so this workflow has produced no check run and no log since the step was added. It has not been running at all. The signature is worth recognising: the run is listed by FILE PATH rather than workflow name, `gh run view --log-failed` returns "log not found", and `gh pr checks` shows nothing, because a parse-rejected workflow creates no check run. Only `gh run list --json conclusion` reveals it. Fix: re-indent the step and its body by four spaces so it sits inside the job's `steps:` list. Nothing else is changed — no action pins, no permissions, no logic. Estate-wide measurement (2026-07-27): this fault affects 49 workflow files across 45 repositories, and every single one of them fails to parse — 100%, not a sample. Compare the 12 files where the same step is correctly indented, which is how the intended shape was determined. Affected workflows are mostly instant-sync.yml (forge propagation), plus boj-build.yml, casket-pages.yml, release.yml, cflite_pr.yml and one codeql.yml. Built with git plumbing directly against origin/HEAD, so no local working tree was involved and no unrelated local changes are included. Co-Authored-By: Claude Opus 5 --- .github/workflows/instant-sync.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/instant-sync.yml b/.github/workflows/instant-sync.yml index 8c3abd1..9ad8fdd 100644 --- a/.github/workflows/instant-sync.yml +++ b/.github/workflows/instant-sync.yml @@ -33,7 +33,7 @@ jobs: - name: Confirm run: echo "::notice::Propagation triggered for ${{ github.event.repository.name }}" - - name: K9-SVC Validation - run: | - echo "K9-SVC validation" - [ -d .machine_readable/contractiles ] && echo "Contractiles present" || echo "No contractiles" + - name: K9-SVC Validation + run: | + echo "K9-SVC validation" + [ -d .machine_readable/contractiles ] && echo "Contractiles present" || echo "No contractiles" \ No newline at end of file From e0c72377b99c403fd313272fcd49a7ca288c7f9a Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 9 Aug 2026 07:02:19 +0100 Subject: [PATCH 03/14] feat: add operation-first Julia accelerator gate --- ARCHITECTURE.md | 50 ++++++- Project.toml | 1 + src/AcceleratorGate.jl | 9 +- src/operations.jl | 307 +++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 75 ++++++++++ 5 files changed, 439 insertions(+), 3 deletions(-) create mode 100644 src/operations.jl diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 607e3d8..857c9f1 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2,13 +2,59 @@ ## Overview -This repository follows a modular, maintainable architecture designed for clarity, scalability, and long-term sustainability. +AcceleratorGate is the Julia admission and compatibility layer for the estate's +operation-first coprocessor runtime. It does not own numerical kernels and a +backend type name is not a capability claim. + +Enaction owns runtime semantics, authoritative/advisory/remote-job policy, and +the Idris2-defined native ABI. AcceleratorGate translates Julia requests into +that operation vocabulary, admits providers using explicit evidence, and +returns execution evidence to Julia consumers. + +## Operation path + +```text +Julia/domain value + | + v +OperationRequest (version, layout, lane, evidence floors) + | + v +deterministic provider planning + | + +-- pure-Zig Enaction native provider + +-- real hardware/provider adapter + +-- explicit reference provider + `-- explicit simulation (only when allow_simulation=true) + | + v +result + ExecutionEvidence +``` + +Provider claims are per operation and include support, determinism, execution +lanes, implementation kind, device class, and optional conformance digest. +Simulations are refused by default. Authoritative claims must be +`canonical_exact`. Remote providers may claim only `remote_job` execution. +Once a provider has been planned, its runtime failure is returned to the +caller; the registry never silently retries another provider. + +`EnactionZigProvider` loads the shared form of the same pure-Zig library used by +the Rust adapter. It validates ABI version, layouts, capability records, status +and execution evidence. There is no C implementation or Julia-owned copy of a +kernel. + +The older device hierarchy and operation-specialty table remain as a legacy +compatibility surface while consumers migrate. Environment flags and a type +such as `TPUBackend` are discovery hints only and must not be presented as +runnable hardware evidence. ## Directory Structure ``` . -├── src/ # Source code +├── src/ +│ ├── AcceleratorGate.jl # legacy compatibility and module surface +│ └── operations.jl # central requests, evidence, planner, providers ├── tests/ # Test suites ├── docs/ # Documentation ├── scripts/ # Utility scripts diff --git a/Project.toml b/Project.toml index bdb078c..c534dda 100644 --- a/Project.toml +++ b/Project.toml @@ -7,6 +7,7 @@ license = "MPL-2.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" [compat] julia = "1.10" diff --git a/src/AcceleratorGate.jl b/src/AcceleratorGate.jl index 2421e3c..bd74a68 100644 --- a/src/AcceleratorGate.jl +++ b/src/AcceleratorGate.jl @@ -28,6 +28,7 @@ backend = select_backend(:matmul, 1_000_000) module AcceleratorGate using Dates +using Libdl export AbstractBackend, JuliaBackend, RustBackend, ZigBackend, CUDABackend, ROCmBackend, MetalBackend, @@ -59,7 +60,13 @@ export AbstractBackend, JuliaBackend, RustBackend, ZigBackend, # Operation registry register_operation!, supports_operation, supported_operations, # Backend specialties - BACKEND_SPECIALTIES, is_specialized + BACKEND_SPECIALTIES, is_specialized, + OperationRequest, CapabilityEvidence, ExecutionEvidence, + AbstractOperationProvider, FunctionProvider, EnactionZigProvider, + register_provider!, clear_provider_registry!, registered_providers, + provider_capabilities, plan_operation, execute_operation + +include("operations.jl") # ============================================================================ # Backend Type Hierarchy diff --git a/src/operations.jl b/src/operations.jl new file mode 100644 index 0000000..f37f098 --- /dev/null +++ b/src/operations.jl @@ -0,0 +1,307 @@ +# SPDX-License-Identifier: MPL-2.0 +# Operation-first admission and execution evidence for estate coprocessors. + +const _SUPPORT_RANK = Dict( + :declared => 1, :discoverable => 2, :loadable => 3, :runnable => 4, + :conformant => 5, :resilient => 6, :deterministic => 7, + :benchmarked => 8, :production_supported => 9, +) +const _DETERMINISM_RANK = Dict(:advisory_only => 1, :tolerance_bounded => 2, :canonical_exact => 3) +const _LANES = (:authoritative, :advisory, :remote_job) +const _FALLBACKS = (:require_named_backend, :require_deterministic_equivalent, :allow_reference, :prefer_accelerated) +const _IMPLEMENTATIONS = (:reference, :native, :hardware, :simulation, :remote) + +"""A backend-neutral, versioned operation request admitted by AcceleratorGate.""" +struct OperationRequest + operation::String + version::VersionNumber + layout::NamedTuple + lane::Symbol + minimum_support::Symbol + minimum_determinism::Symbol + fallback::Symbol + named_provider::Union{Nothing,String} + allow_simulation::Bool + function OperationRequest(operation::AbstractString; + version=v"1.0.0", layout=(;), lane=:advisory, + minimum_support=:conformant, minimum_determinism=:tolerance_bounded, + fallback=:prefer_accelerated, named_provider=nothing, + allow_simulation=false) + isempty(operation) && throw(ArgumentError("operation id must not be empty")) + lane in _LANES || throw(ArgumentError("invalid execution lane: $lane")) + haskey(_SUPPORT_RANK, minimum_support) || throw(ArgumentError("invalid support level: $minimum_support")) + haskey(_DETERMINISM_RANK, minimum_determinism) || throw(ArgumentError("invalid determinism: $minimum_determinism")) + fallback in _FALLBACKS || throw(ArgumentError("invalid fallback policy: $fallback")) + fallback === :require_named_backend && named_provider === nothing && + throw(ArgumentError("require_named_backend needs named_provider")) + new(String(operation), VersionNumber(version), layout, lane, minimum_support, + minimum_determinism, fallback, + named_provider === nothing ? nothing : String(named_provider), allow_simulation) + end +end + +"""Auditable support claim for one provider/operation pair.""" +struct CapabilityEvidence + provider_id::String + provider_version::VersionNumber + operation::String + operation_version::VersionNumber + lanes::Tuple{Vararg{Symbol}} + support::Symbol + determinism::Symbol + implementation::Symbol + device_class::Symbol + conformance_digest::Union{Nothing,String} + function CapabilityEvidence(provider_id, provider_version, operation, operation_version; + lanes=(:advisory,), support=:declared, determinism=:advisory_only, + implementation=:simulation, device_class=:cpu, conformance_digest=nothing) + isempty(provider_id) && throw(ArgumentError("provider id must not be empty")) + isempty(operation) && throw(ArgumentError("operation id must not be empty")) + isempty(lanes) && throw(ArgumentError("at least one execution lane is required")) + all(lane -> lane in _LANES, lanes) || throw(ArgumentError("invalid execution lane")) + haskey(_SUPPORT_RANK, support) || throw(ArgumentError("invalid support level: $support")) + haskey(_DETERMINISM_RANK, determinism) || throw(ArgumentError("invalid determinism: $determinism")) + implementation in _IMPLEMENTATIONS || throw(ArgumentError("invalid implementation kind: $implementation")) + implementation === :remote && !all(==(:remote_job), lanes) && + throw(ArgumentError("remote providers may claim only the remote_job lane")) + implementation !== :remote && :remote_job in lanes && + throw(ArgumentError("only remote providers may claim remote_job")) + :authoritative in lanes && determinism !== :canonical_exact && + throw(ArgumentError("authoritative capability must be canonical_exact")) + new(String(provider_id), VersionNumber(provider_version), String(operation), + VersionNumber(operation_version), Tuple(lanes), support, determinism, + implementation, device_class, + conformance_digest === nothing ? nothing : String(conformance_digest)) + end +end + +"""Evidence returned only after successful execution by the planned provider.""" +struct ExecutionEvidence + provider_id::String + provider_version::VersionNumber + operation::String + operation_version::VersionNumber + lane::Symbol + support::Symbol + determinism::Symbol + implementation::Symbol +end + +abstract type AbstractOperationProvider end + +"""Provider backed by a Julia callback; useful for real adapters and explicit simulators.""" +struct FunctionProvider <: AbstractOperationProvider + id::String + version::VersionNumber + claims::Vector{CapabilityEvidence} + callback::Function + function FunctionProvider(id, version, claims, callback) + all(claim -> claim.provider_id == id && claim.provider_version == VersionNumber(version), claims) || + throw(ArgumentError("every capability must name the provider and version")) + new(String(id), VersionNumber(version), collect(claims), callback) + end +end + +FunctionProvider(callback::Function, id, version, claims) = FunctionProvider(id, version, claims, callback) + +provider_id(provider::FunctionProvider) = provider.id +provider_capabilities(provider::FunctionProvider) = copy(provider.claims) +_execute_provider(provider::FunctionProvider, request::OperationRequest, args...) = provider.callback(request, args...) + +const _OPERATION_PROVIDERS = AbstractOperationProvider[] +const _OPERATION_PROVIDER_LOCK = ReentrantLock() + +registered_providers() = lock(_OPERATION_PROVIDER_LOCK) do + copy(_OPERATION_PROVIDERS) +end +clear_provider_registry!() = lock(_OPERATION_PROVIDER_LOCK) do + empty!(_OPERATION_PROVIDERS) +end + +function register_provider!(provider::AbstractOperationProvider) + id = provider_id(provider) + isempty(provider_capabilities(provider)) && throw(ArgumentError("provider must claim at least one operation")) + lock(_OPERATION_PROVIDER_LOCK) do + any(existing -> provider_id(existing) == id, _OPERATION_PROVIDERS) && + throw(ArgumentError("duplicate operation provider id: $id")) + push!(_OPERATION_PROVIDERS, provider) + end + provider +end + +function _compatible(claim::CapabilityEvidence, request::OperationRequest) + claim.operation == request.operation || return false + claim.operation_version.major == request.version.major || return false + claim.operation_version.minor >= request.version.minor || return false + request.lane in claim.lanes || return false + _SUPPORT_RANK[claim.support] >= _SUPPORT_RANK[request.minimum_support] || return false + _DETERMINISM_RANK[claim.determinism] >= _DETERMINISM_RANK[request.minimum_determinism] || return false + request.lane === :authoritative && claim.determinism !== :canonical_exact && return false + claim.implementation === :simulation && !request.allow_simulation && return false + request.named_provider !== nothing && claim.provider_id != request.named_provider && return false + request.fallback === :require_deterministic_equivalent && claim.determinism !== :canonical_exact && return false + request.fallback === :allow_reference && claim.implementation !== :reference && return false + true +end + +function _preference(claim::CapabilityEvidence) + kind = Dict(:hardware => 5, :native => 4, :remote => 3, :reference => 2, :simulation => 1)[claim.implementation] + (kind, _SUPPORT_RANK[claim.support], _DETERMINISM_RANK[claim.determinism]) +end + +"""Select one provider deterministically. Registration order never breaks ties.""" +function plan_operation(request::OperationRequest) + candidates = Tuple{AbstractOperationProvider,CapabilityEvidence}[] + lock(_OPERATION_PROVIDER_LOCK) do + for provider in _OPERATION_PROVIDERS, claim in provider_capabilities(provider) + _compatible(claim, request) && push!(candidates, (provider, claim)) + end + end + isempty(candidates) && throw(ErrorException("no compatible provider for $(request.operation)")) + sort!(candidates; by=entry -> begin + preference = _preference(entry[2]) + (-preference[1], -preference[2], -preference[3], entry[2].provider_id) + end) + candidates[1] +end + +"""Execute exactly the planned provider. A runtime failure is never a fallback signal.""" +function execute_operation(request::OperationRequest, args...) + provider, claim = plan_operation(request) + value = _execute_provider(provider, request, args...) + evidence = ExecutionEvidence(claim.provider_id, claim.provider_version, + claim.operation, request.version, request.lane, claim.support, + claim.determinism, claim.implementation) + value, evidence +end + +# Enaction v1 C-compatible structs. Idris2 remains their authority; these +# assertions make drift fail at Julia load rather than corrupting a call. +struct _EnactionRequest + abi_major::UInt16; abi_minor::UInt16; operation_major::UInt16; operation_minor::UInt16 + operation::UInt32; lane::UInt32; minimum_support::UInt32; minimum_determinism::UInt32 + layout::UInt32; reserved::UInt32; dim0::UInt64; dim1::UInt64; dim2::UInt64 +end +struct _EnactionBufferIn + data::Ptr{Float32}; len::UInt64 +end +struct _EnactionBufferOut + data::Ptr{Float32}; len::UInt64 +end +struct _EnactionCapability + abi_major::UInt16; abi_minor::UInt16; operation_major::UInt16; operation_minor::UInt16 + operation::UInt32; support::UInt32; determinism::UInt32; backend_id::UInt32 + device_class::UInt32; flags::UInt32 +end +struct _EnactionEvidence + abi_major::UInt16; abi_minor::UInt16; operation_major::UInt16; operation_minor::UInt16 + operation::UInt32; backend_id::UInt32; support::UInt32; determinism::UInt32 +end + +sizeof(_EnactionRequest) == 56 || error("Enaction Request ABI drift") +sizeof(_EnactionBufferIn) == 16 || error("Enaction buffer ABI drift") +sizeof(_EnactionCapability) == 32 || error("Enaction Capability ABI drift") +sizeof(_EnactionEvidence) == 24 || error("Enaction Evidence ABI drift") + +const _OP_CODE = Dict( + "enaction.tensor.f32.relu" => UInt32(3), "enaction.tensor.f32.relu6" => UInt32(4), + "enaction.tensor.f32.matmul" => UInt32(5), "enaction.tensor.f32.add" => UInt32(6), + "enaction.tensor.f32.mul" => UInt32(7), +) +const _CODE_OP = Dict(value => key for (key, value) in _OP_CODE) +const _SUPPORT_CODE = Dict(key => UInt32(value) for (key, value) in _SUPPORT_RANK) +const _DETERMINISM_CODE = Dict(key => UInt32(value) for (key, value) in _DETERMINISM_RANK) + +mutable struct EnactionZigProvider <: AbstractOperationProvider + id::String + version::VersionNumber + path::String + handle::Ptr{Cvoid} + claims::Vector{CapabilityEvidence} + unary::Ptr{Cvoid} + binary::Ptr{Cvoid} +end + +provider_id(provider::EnactionZigProvider) = provider.id +provider_capabilities(provider::EnactionZigProvider) = copy(provider.claims) + +function EnactionZigProvider(path::AbstractString) + isfile(path) || throw(ArgumentError("Enaction Zig library not found: $path")) + handle = Libdl.dlopen(path) + abi_version = ccall(Libdl.dlsym(handle, :enaction_accel_abi_version), UInt32, ()) + abi_version == 0x00010000 || throw(ErrorException("unsupported Enaction accelerator ABI: $abi_version")) + count = ccall(Libdl.dlsym(handle, :enaction_accel_capability_count), UInt32, ()) + at = Libdl.dlsym(handle, :enaction_accel_capability_at) + claims = CapabilityEvidence[] + for index in UInt32(0):(count - UInt32(1)) + raw = Ref{_EnactionCapability}() + status = ccall(at, UInt32, (UInt32, Ref{_EnactionCapability}), index, raw) + status == 0 || throw(ErrorException("capability query failed with status $status")) + raw[].abi_major == 1 && raw[].abi_minor == 0 && + raw[].operation_major == 1 && raw[].operation_minor == 0 && + raw[].backend_id == 1 && raw[].device_class == 1 || + throw(ErrorException("invalid Enaction capability evidence at index $index")) + operation = get(_CODE_OP, raw[].operation, nothing) + operation === nothing && continue # fixed-i32 uses a different Julia buffer surface + support = Symbol(first(key for (key, value) in _SUPPORT_CODE if value == raw[].support)) + determinism = Symbol(first(key for (key, value) in _DETERMINISM_CODE if value == raw[].determinism)) + push!(claims, CapabilityEvidence("enaction.cpu.zig.scalar", v"1.0.0", operation, v"1.0.0"; + lanes=(:advisory,), support, determinism, implementation=:native, + device_class=:cpu, conformance_digest=nothing)) + end + EnactionZigProvider("enaction.cpu.zig.scalar", v"1.0.0", String(path), handle, claims, + Libdl.dlsym(handle, :enaction_accel_execute_f32), + Libdl.dlsym(handle, :enaction_accel_execute_f32_binary)) +end + +function _native_layout(request::OperationRequest) + if request.operation == "enaction.tensor.f32.matmul" + all(key -> haskey(request.layout, key), (:m, :k, :n)) || throw(ArgumentError("matmul layout needs m, k and n")) + UInt32(2), UInt64(request.layout.m), UInt64(request.layout.k), UInt64(request.layout.n) + else + haskey(request.layout, :len) || throw(ArgumentError("vector layout needs len")) + UInt32(3), UInt64(request.layout.len), UInt64(0), UInt64(0) + end +end + +function _execute_provider(provider::EnactionZigProvider, request::OperationRequest, args...) + code = get(_OP_CODE, request.operation, nothing) + code === nothing && throw(ArgumentError("unsupported native operation: $(request.operation)")) + layout, dim0, dim1, dim2 = _native_layout(request) + raw_request = Ref(_EnactionRequest(1, 0, UInt16(request.version.major), UInt16(request.version.minor), + code, 2, _SUPPORT_CODE[request.minimum_support], _DETERMINISM_CODE[request.minimum_determinism], + layout, 0, dim0, dim1, dim2)) + evidence = Ref{_EnactionEvidence}() + inputs = if request.operation == "enaction.tensor.f32.matmul" + map(value -> vec(permutedims(Float32.(value))), args) + else + map(value -> vec(Float32.(value)), args) + end + expected = request.operation == "enaction.tensor.f32.matmul" ? Int(dim0 * dim2) : Int(dim0) + output = Vector{Float32}(undef, expected) + output_buffer = Ref(_EnactionBufferOut(pointer(output), UInt64(length(output)))) + status = GC.@preserve inputs output begin + buffers = map(value -> Ref(_EnactionBufferIn(pointer(value), UInt64(length(value)))), inputs) + if length(buffers) == 1 + ccall(provider.unary, UInt32, + (Ref{_EnactionRequest}, Ref{_EnactionBufferIn}, Ref{_EnactionBufferOut}, Ref{_EnactionEvidence}), + raw_request, buffers[1], output_buffer, evidence) + elseif length(buffers) == 2 + ccall(provider.binary, UInt32, + (Ref{_EnactionRequest}, Ref{_EnactionBufferIn}, Ref{_EnactionBufferIn}, Ref{_EnactionBufferOut}, Ref{_EnactionEvidence}), + raw_request, buffers[1], buffers[2], output_buffer, evidence) + else + throw(ArgumentError("native tensor operations take one or two inputs")) + end + end + status == 0 || throw(ErrorException("Enaction Zig operation failed with ABI status $status")) + raw_evidence = evidence[] + raw_evidence.abi_major == 1 && raw_evidence.abi_minor == 0 && + raw_evidence.operation_major == request.version.major && + raw_evidence.operation_minor == request.version.minor && + raw_evidence.operation == code && raw_evidence.backend_id == 1 && + raw_evidence.support >= _SUPPORT_CODE[request.minimum_support] && + raw_evidence.determinism >= _DETERMINISM_CODE[request.minimum_determinism] || + throw(ErrorException("invalid Enaction execution evidence")) + request.operation == "enaction.tensor.f32.matmul" ? reshape(output, Int(dim2), Int(dim0))' |> Matrix : output +end diff --git a/test/runtests.jl b/test/runtests.jl index 8ad0756..c7d83a8 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -288,6 +288,81 @@ using AcceleratorGate @test is_specialized(JuliaBackend(), :matmul) == false end + @testset "Operation-first provider admission" begin + clear_provider_registry!() + simulation_claim = CapabilityEvidence( + "test.simulated.tpu", v"1.0.0", "enaction.tensor.f32.mul", v"1.0.0"; + lanes=(:advisory,), support=:conformant, + determinism=:tolerance_bounded, implementation=:simulation, + device_class=:tpu, + ) + simulation = FunctionProvider("test.simulated.tpu", v"1.0.0", [simulation_claim]) do _, left, right + left .* right + end + register_provider!(simulation) + + refused = OperationRequest("enaction.tensor.f32.mul"; + layout=(len=2,), allow_simulation=false) + @test_throws ErrorException plan_operation(refused) + + admitted = OperationRequest("enaction.tensor.f32.mul"; + layout=(len=2,), allow_simulation=true) + value, evidence = execute_operation(admitted, Float32[2, 3], Float32[4, 5]) + @test value == Float32[8, 15] + @test evidence.provider_id == "test.simulated.tpu" + @test evidence.implementation == :simulation + @test evidence.lane == :advisory + + @test_throws ArgumentError CapabilityEvidence( + "bad.tpu", v"1.0.0", "enaction.tensor.f32.mul", v"1.0.0"; + lanes=(:authoritative,), determinism=:tolerance_bounded, + ) + @test_throws ArgumentError register_provider!(simulation) + clear_provider_registry!() + end + + @testset "Runtime failure never silently retries" begin + clear_provider_registry!() + claim(id, implementation) = CapabilityEvidence( + id, v"1.0.0", "enaction.tensor.f32.add", v"1.0.0"; + lanes=(:advisory,), support=:resilient, + determinism=:tolerance_bounded, implementation, + ) + failing = FunctionProvider("a.hardware", v"1.0.0", [claim("a.hardware", :hardware)]) do _, _... + error("planted provider failure") + end + reference = FunctionProvider("z.reference", v"1.0.0", [claim("z.reference", :reference)]) do _, left, right + left .+ right + end + register_provider!(reference) + register_provider!(failing) + request = OperationRequest("enaction.tensor.f32.add"; layout=(len=1,)) + @test_throws ErrorException execute_operation(request, Float32[1], Float32[2]) + clear_provider_registry!() + end + + if haskey(ENV, "ENACTION_ACCELERATOR_LIB") + @testset "Enaction pure-Zig provider" begin + clear_provider_registry!() + provider = EnactionZigProvider(ENV["ENACTION_ACCELERATOR_LIB"]) + register_provider!(provider) + @test length(provider_capabilities(provider)) == 5 + + request = OperationRequest("enaction.tensor.f32.matmul"; + layout=(m=2, k=3, n=2), minimum_support=:resilient) + output, evidence = execute_operation(request, + Float32[1 2 3; 4 5 6], Float32[7 8; 9 10; 11 12]) + @test output == Float32[58 64; 139 154] + @test evidence.provider_id == "enaction.cpu.zig.scalar" + @test evidence.implementation == :native + + overflow = OperationRequest("enaction.tensor.f32.mul"; + layout=(len=1,), minimum_support=:resilient) + @test_throws ErrorException execute_operation(overflow, Float32[floatmax(Float32)], Float32[2]) + clear_provider_registry!() + end + end + # ======================================================================== # Platform Detection Tests # ======================================================================== From c5da56c9bcd1299d9fe7bcb292a7dac450fc67ca Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 9 Aug 2026 07:17:44 +0100 Subject: [PATCH 04/14] docs: add BerryWiki coprocessor notebook --- .machine_readable/6a2/STATE.a2ml | 8 ++++++++ docs/berrywiki/ABI.md | 18 ++++++++++++++++++ docs/berrywiki/Architecture.md | 18 ++++++++++++++++++ docs/berrywiki/Axiom-Kernels.md | 18 ++++++++++++++++++ docs/berrywiki/Backends.md | 18 ++++++++++++++++++ docs/berrywiki/Evidence.md | 18 ++++++++++++++++++ docs/berrywiki/Home.md | 19 +++++++++++++++++++ docs/berrywiki/Kernels.md | 18 ++++++++++++++++++ docs/berrywiki/Machine-Index.md | 18 ++++++++++++++++++ docs/berrywiki/Operations.md | 18 ++++++++++++++++++ docs/berrywiki/Performance.md | 18 ++++++++++++++++++ docs/berrywiki/Roadmap.md | 18 ++++++++++++++++++ docs/berrywiki/Runtime.md | 18 ++++++++++++++++++ docs/berrywiki/Security.md | 18 ++++++++++++++++++ docs/berrywiki/Simulation.md | 18 ++++++++++++++++++ docs/berrywiki/Testing.md | 18 ++++++++++++++++++ docs/berrywiki/UMS-Integration.md | 18 ++++++++++++++++++ docs/berrywiki/_Sidebar.md | 18 ++++++++++++++++++ 18 files changed, 315 insertions(+) create mode 100644 docs/berrywiki/ABI.md create mode 100644 docs/berrywiki/Architecture.md create mode 100644 docs/berrywiki/Axiom-Kernels.md create mode 100644 docs/berrywiki/Backends.md create mode 100644 docs/berrywiki/Evidence.md create mode 100644 docs/berrywiki/Home.md create mode 100644 docs/berrywiki/Kernels.md create mode 100644 docs/berrywiki/Machine-Index.md create mode 100644 docs/berrywiki/Operations.md create mode 100644 docs/berrywiki/Performance.md create mode 100644 docs/berrywiki/Roadmap.md create mode 100644 docs/berrywiki/Runtime.md create mode 100644 docs/berrywiki/Security.md create mode 100644 docs/berrywiki/Simulation.md create mode 100644 docs/berrywiki/Testing.md create mode 100644 docs/berrywiki/UMS-Integration.md create mode 100644 docs/berrywiki/_Sidebar.md diff --git a/.machine_readable/6a2/STATE.a2ml b/.machine_readable/6a2/STATE.a2ml index e09f348..1e7c42c 100644 --- a/.machine_readable/6a2/STATE.a2ml +++ b/.machine_readable/6a2/STATE.a2ml @@ -7,8 +7,16 @@ project = "AcceleratorGate.jl" version = "0.1.0" last-updated = "2026-03-15" status = "active" +wiki = "docs/berrywiki/" +wiki-pages = 16 +wiki-tool = "metadatastician/berrywiki" [project-context] name = "AcceleratorGate.jl" completion-percentage = 5 phase = "alpha" + +[coprocessor-documentation] +human-index = "docs/berrywiki/Home.md" +machine-index = "docs/berrywiki/Machine-Index.md" +scope = "provider admission, deterministic planning, execution evidence, and shared Zig ABI" diff --git a/docs/berrywiki/ABI.md b/docs/berrywiki/ABI.md new file mode 100644 index 0000000..d759058 --- /dev/null +++ b/docs/berrywiki/ABI.md @@ -0,0 +1,18 @@ + + +# ABI + +Stable Idris2-facing and Zig FFI layout rules. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Architecture.md b/docs/berrywiki/Architecture.md new file mode 100644 index 0000000..62ebd2e --- /dev/null +++ b/docs/berrywiki/Architecture.md @@ -0,0 +1,18 @@ + + +# Architecture + +Boundaries, ownership, and data flow. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Axiom-Kernels.md b/docs/berrywiki/Axiom-Kernels.md new file mode 100644 index 0000000..1787574 --- /dev/null +++ b/docs/berrywiki/Axiom-Kernels.md @@ -0,0 +1,18 @@ + + +# Axiom-Kernels + +Axiom-derived pointwise, binary, and attention coverage. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Backends.md b/docs/berrywiki/Backends.md new file mode 100644 index 0000000..f441343 --- /dev/null +++ b/docs/berrywiki/Backends.md @@ -0,0 +1,18 @@ + + +# Backends + +Backend/provider registration and selection. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Evidence.md b/docs/berrywiki/Evidence.md new file mode 100644 index 0000000..b4741e9 --- /dev/null +++ b/docs/berrywiki/Evidence.md @@ -0,0 +1,18 @@ + + +# Evidence + +Capability and execution evidence requirements. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Home.md b/docs/berrywiki/Home.md new file mode 100644 index 0000000..2984779 --- /dev/null +++ b/docs/berrywiki/Home.md @@ -0,0 +1,19 @@ + + +# AcceleratorGate.jl + +Julia operation-first admission and evidence control plane. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +This BerryWiki notebook is the human-facing index; the repository's machine-readable state file is authoritative for automation. + diff --git a/docs/berrywiki/Kernels.md b/docs/berrywiki/Kernels.md new file mode 100644 index 0000000..10d1c9d --- /dev/null +++ b/docs/berrywiki/Kernels.md @@ -0,0 +1,18 @@ + + +# Kernels + +Kernel families, layouts, and numerical contracts. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Machine-Index.md b/docs/berrywiki/Machine-Index.md new file mode 100644 index 0000000..650cba7 --- /dev/null +++ b/docs/berrywiki/Machine-Index.md @@ -0,0 +1,18 @@ + + +# Machine-Index + +Machine-readable inventory and automation entry point. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Operations.md b/docs/berrywiki/Operations.md new file mode 100644 index 0000000..3d302ba --- /dev/null +++ b/docs/berrywiki/Operations.md @@ -0,0 +1,18 @@ + + +# Operations + +Canonical operation names and request semantics. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Performance.md b/docs/berrywiki/Performance.md new file mode 100644 index 0000000..0a25477 --- /dev/null +++ b/docs/berrywiki/Performance.md @@ -0,0 +1,18 @@ + + +# Performance + +Benchmarking, determinism, and tuning guidance. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Roadmap.md b/docs/berrywiki/Roadmap.md new file mode 100644 index 0000000..b0f0a31 --- /dev/null +++ b/docs/berrywiki/Roadmap.md @@ -0,0 +1,18 @@ + + +# Roadmap + +Near-term implementation and admission milestones. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Runtime.md b/docs/berrywiki/Runtime.md new file mode 100644 index 0000000..600f00f --- /dev/null +++ b/docs/berrywiki/Runtime.md @@ -0,0 +1,18 @@ + + +# Runtime + +Lifecycle, loading, and failure terminality. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Security.md b/docs/berrywiki/Security.md new file mode 100644 index 0000000..b65d8f2 --- /dev/null +++ b/docs/berrywiki/Security.md @@ -0,0 +1,18 @@ + + +# Security + +Trust boundaries, validation, and unsafe inputs. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Simulation.md b/docs/berrywiki/Simulation.md new file mode 100644 index 0000000..7628d31 --- /dev/null +++ b/docs/berrywiki/Simulation.md @@ -0,0 +1,18 @@ + + +# Simulation + +Rules for simulation, refusal, and conformance claims. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Testing.md b/docs/berrywiki/Testing.md new file mode 100644 index 0000000..9d751f0 --- /dev/null +++ b/docs/berrywiki/Testing.md @@ -0,0 +1,18 @@ + + +# Testing + +Local tests, integration tests, and acceptance gates. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/UMS-Integration.md b/docs/berrywiki/UMS-Integration.md new file mode 100644 index 0000000..7059d79 --- /dev/null +++ b/docs/berrywiki/UMS-Integration.md @@ -0,0 +1,18 @@ + + +# UMS-Integration + +How the universal model space contract is consumed. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/_Sidebar.md b/docs/berrywiki/_Sidebar.md new file mode 100644 index 0000000..a2eadce --- /dev/null +++ b/docs/berrywiki/_Sidebar.md @@ -0,0 +1,18 @@ +# Notebook + +- [AcceleratorGate.jl](Home) +- [Architecture](Architecture) +- [Operations](Operations) +- [Backends](Backends) +- [Kernels](Kernels) +- [Evidence](Evidence) +- [ABI](ABI) +- [UMS-Integration](UMS-Integration) +- [Simulation](Simulation) +- [Axiom-Kernels](Axiom-Kernels) +- [Runtime](Runtime) +- [Testing](Testing) +- [Security](Security) +- [Performance](Performance) +- [Roadmap](Roadmap) +- [Machine-Index](Machine-Index) From ac5302ffa49751be6af24a5668cf6918705a90c9 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 9 Aug 2026 07:50:30 +0100 Subject: [PATCH 05/14] chore: refresh governance metadata --- GOVERNANCE.md | 2 +- MAINTAINERS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GOVERNANCE.md b/GOVERNANCE.md index e27364c..3d41c87 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -57,4 +57,4 @@ By submitting a pull request, you agree to license your contributions accordingl --- -*Last updated: 2026-07-18* +*Last updated: 2026-08-09* diff --git a/MAINTAINERS b/MAINTAINERS index 37f6411..c0b34bf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -40,4 +40,4 @@ To become a maintainer: --- -*Last updated: 2026-07-18* +*Last updated: 2026-08-09* From 7651f722f128241b4a5f440bbcc0bf2b618279bb Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 26 Jul 2026 16:07:38 +0100 Subject: [PATCH 06/14] chore: update guix.scm from squisher-corpus --- guix.scm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/guix.scm b/guix.scm index 83e4fe8..c6dd7be 100644 --- a/guix.scm +++ b/guix.scm @@ -1,5 +1,5 @@ ; SPDX-License-Identifier: MPL-2.0 -;; guix.scm — GNU Guix package definition for AcceleratorGate.jl +;; guix.scm — GNU Guix package definition for squisher-corpus ;; Usage: guix shell -f guix.scm (use-modules (guix packages) @@ -7,12 +7,12 @@ (guix licenses)) (package - (name "AcceleratorGate.jl") + (name "squisher-corpus") (version "0.1.0") (source #f) (build-system gnu-build-system) - (synopsis "AcceleratorGate.jl") - (description "AcceleratorGate.jl — part of the hyperpolymath ecosystem.") - (home-page "https://github.com/hyperpolymath/AcceleratorGate.jl") - (license ((@@ (guix licenses) license) "MPL-2.0" - "https://www.mozilla.org/MPL/2.0/"))) + (synopsis "squisher-corpus") + (description "squisher-corpus — part of the hyperpolymath ecosystem.") + (home-page "https://github.com/hyperpolymath/squisher-corpus") + (license ((@@ (guix licenses) license) "PMPL-1.0-or-later" + "https://github.com/hyperpolymath/palimpsest-license"))) From a224a23ef322b0378dc37e7255cd68ad4840fc61 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 9 Aug 2026 07:02:19 +0100 Subject: [PATCH 07/14] feat: add operation-first Julia accelerator gate --- ARCHITECTURE.md | 93 +++++++++++++ Project.toml | 1 + src/AcceleratorGate.jl | 9 +- src/operations.jl | 307 +++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 75 ++++++++++ 5 files changed, 484 insertions(+), 1 deletion(-) create mode 100644 ARCHITECTURE.md create mode 100644 src/operations.jl diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..857c9f1 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,93 @@ +# Architecture + +## Overview + +AcceleratorGate is the Julia admission and compatibility layer for the estate's +operation-first coprocessor runtime. It does not own numerical kernels and a +backend type name is not a capability claim. + +Enaction owns runtime semantics, authoritative/advisory/remote-job policy, and +the Idris2-defined native ABI. AcceleratorGate translates Julia requests into +that operation vocabulary, admits providers using explicit evidence, and +returns execution evidence to Julia consumers. + +## Operation path + +```text +Julia/domain value + | + v +OperationRequest (version, layout, lane, evidence floors) + | + v +deterministic provider planning + | + +-- pure-Zig Enaction native provider + +-- real hardware/provider adapter + +-- explicit reference provider + `-- explicit simulation (only when allow_simulation=true) + | + v +result + ExecutionEvidence +``` + +Provider claims are per operation and include support, determinism, execution +lanes, implementation kind, device class, and optional conformance digest. +Simulations are refused by default. Authoritative claims must be +`canonical_exact`. Remote providers may claim only `remote_job` execution. +Once a provider has been planned, its runtime failure is returned to the +caller; the registry never silently retries another provider. + +`EnactionZigProvider` loads the shared form of the same pure-Zig library used by +the Rust adapter. It validates ABI version, layouts, capability records, status +and execution evidence. There is no C implementation or Julia-owned copy of a +kernel. + +The older device hierarchy and operation-specialty table remain as a legacy +compatibility surface while consumers migrate. Environment flags and a type +such as `TPUBackend` are discovery hints only and must not be presented as +runnable hardware evidence. + +## Directory Structure + +``` +. +├── src/ +│ ├── AcceleratorGate.jl # legacy compatibility and module surface +│ └── operations.jl # central requests, evidence, planner, providers +├── tests/ # Test suites +├── docs/ # Documentation +├── scripts/ # Utility scripts +├── config/ # Configuration files +├── LICENSE # License file +├── LICENSES/ # Full license texts +└── README.adoc # Project documentation +``` + +## Design Principles + +- **Separation of Concerns**: Each module has a single responsibility +- **Testability**: Code is written to be easily testable +- **Documentation**: All public APIs are documented +- **Configuration**: Environment-specific settings are externalized + +## Dependencies + +- External dependencies are minimized and clearly declared +- Version pinning is used for reproducibility + +## Security Considerations + +- Sensitive data is never committed to the repository +- Secrets are managed through environment variables or secure vaults +- Regular dependency audits are performed + +## Maintainability + +- Code follows consistent style guidelines +- Pull requests require review and CI checks +- Issues and discussions are tracked transparently + +--- + +*Last updated: 2026-07-18* diff --git a/Project.toml b/Project.toml index bdb078c..c534dda 100644 --- a/Project.toml +++ b/Project.toml @@ -7,6 +7,7 @@ license = "MPL-2.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" [compat] julia = "1.10" diff --git a/src/AcceleratorGate.jl b/src/AcceleratorGate.jl index 2421e3c..bd74a68 100644 --- a/src/AcceleratorGate.jl +++ b/src/AcceleratorGate.jl @@ -28,6 +28,7 @@ backend = select_backend(:matmul, 1_000_000) module AcceleratorGate using Dates +using Libdl export AbstractBackend, JuliaBackend, RustBackend, ZigBackend, CUDABackend, ROCmBackend, MetalBackend, @@ -59,7 +60,13 @@ export AbstractBackend, JuliaBackend, RustBackend, ZigBackend, # Operation registry register_operation!, supports_operation, supported_operations, # Backend specialties - BACKEND_SPECIALTIES, is_specialized + BACKEND_SPECIALTIES, is_specialized, + OperationRequest, CapabilityEvidence, ExecutionEvidence, + AbstractOperationProvider, FunctionProvider, EnactionZigProvider, + register_provider!, clear_provider_registry!, registered_providers, + provider_capabilities, plan_operation, execute_operation + +include("operations.jl") # ============================================================================ # Backend Type Hierarchy diff --git a/src/operations.jl b/src/operations.jl new file mode 100644 index 0000000..f37f098 --- /dev/null +++ b/src/operations.jl @@ -0,0 +1,307 @@ +# SPDX-License-Identifier: MPL-2.0 +# Operation-first admission and execution evidence for estate coprocessors. + +const _SUPPORT_RANK = Dict( + :declared => 1, :discoverable => 2, :loadable => 3, :runnable => 4, + :conformant => 5, :resilient => 6, :deterministic => 7, + :benchmarked => 8, :production_supported => 9, +) +const _DETERMINISM_RANK = Dict(:advisory_only => 1, :tolerance_bounded => 2, :canonical_exact => 3) +const _LANES = (:authoritative, :advisory, :remote_job) +const _FALLBACKS = (:require_named_backend, :require_deterministic_equivalent, :allow_reference, :prefer_accelerated) +const _IMPLEMENTATIONS = (:reference, :native, :hardware, :simulation, :remote) + +"""A backend-neutral, versioned operation request admitted by AcceleratorGate.""" +struct OperationRequest + operation::String + version::VersionNumber + layout::NamedTuple + lane::Symbol + minimum_support::Symbol + minimum_determinism::Symbol + fallback::Symbol + named_provider::Union{Nothing,String} + allow_simulation::Bool + function OperationRequest(operation::AbstractString; + version=v"1.0.0", layout=(;), lane=:advisory, + minimum_support=:conformant, minimum_determinism=:tolerance_bounded, + fallback=:prefer_accelerated, named_provider=nothing, + allow_simulation=false) + isempty(operation) && throw(ArgumentError("operation id must not be empty")) + lane in _LANES || throw(ArgumentError("invalid execution lane: $lane")) + haskey(_SUPPORT_RANK, minimum_support) || throw(ArgumentError("invalid support level: $minimum_support")) + haskey(_DETERMINISM_RANK, minimum_determinism) || throw(ArgumentError("invalid determinism: $minimum_determinism")) + fallback in _FALLBACKS || throw(ArgumentError("invalid fallback policy: $fallback")) + fallback === :require_named_backend && named_provider === nothing && + throw(ArgumentError("require_named_backend needs named_provider")) + new(String(operation), VersionNumber(version), layout, lane, minimum_support, + minimum_determinism, fallback, + named_provider === nothing ? nothing : String(named_provider), allow_simulation) + end +end + +"""Auditable support claim for one provider/operation pair.""" +struct CapabilityEvidence + provider_id::String + provider_version::VersionNumber + operation::String + operation_version::VersionNumber + lanes::Tuple{Vararg{Symbol}} + support::Symbol + determinism::Symbol + implementation::Symbol + device_class::Symbol + conformance_digest::Union{Nothing,String} + function CapabilityEvidence(provider_id, provider_version, operation, operation_version; + lanes=(:advisory,), support=:declared, determinism=:advisory_only, + implementation=:simulation, device_class=:cpu, conformance_digest=nothing) + isempty(provider_id) && throw(ArgumentError("provider id must not be empty")) + isempty(operation) && throw(ArgumentError("operation id must not be empty")) + isempty(lanes) && throw(ArgumentError("at least one execution lane is required")) + all(lane -> lane in _LANES, lanes) || throw(ArgumentError("invalid execution lane")) + haskey(_SUPPORT_RANK, support) || throw(ArgumentError("invalid support level: $support")) + haskey(_DETERMINISM_RANK, determinism) || throw(ArgumentError("invalid determinism: $determinism")) + implementation in _IMPLEMENTATIONS || throw(ArgumentError("invalid implementation kind: $implementation")) + implementation === :remote && !all(==(:remote_job), lanes) && + throw(ArgumentError("remote providers may claim only the remote_job lane")) + implementation !== :remote && :remote_job in lanes && + throw(ArgumentError("only remote providers may claim remote_job")) + :authoritative in lanes && determinism !== :canonical_exact && + throw(ArgumentError("authoritative capability must be canonical_exact")) + new(String(provider_id), VersionNumber(provider_version), String(operation), + VersionNumber(operation_version), Tuple(lanes), support, determinism, + implementation, device_class, + conformance_digest === nothing ? nothing : String(conformance_digest)) + end +end + +"""Evidence returned only after successful execution by the planned provider.""" +struct ExecutionEvidence + provider_id::String + provider_version::VersionNumber + operation::String + operation_version::VersionNumber + lane::Symbol + support::Symbol + determinism::Symbol + implementation::Symbol +end + +abstract type AbstractOperationProvider end + +"""Provider backed by a Julia callback; useful for real adapters and explicit simulators.""" +struct FunctionProvider <: AbstractOperationProvider + id::String + version::VersionNumber + claims::Vector{CapabilityEvidence} + callback::Function + function FunctionProvider(id, version, claims, callback) + all(claim -> claim.provider_id == id && claim.provider_version == VersionNumber(version), claims) || + throw(ArgumentError("every capability must name the provider and version")) + new(String(id), VersionNumber(version), collect(claims), callback) + end +end + +FunctionProvider(callback::Function, id, version, claims) = FunctionProvider(id, version, claims, callback) + +provider_id(provider::FunctionProvider) = provider.id +provider_capabilities(provider::FunctionProvider) = copy(provider.claims) +_execute_provider(provider::FunctionProvider, request::OperationRequest, args...) = provider.callback(request, args...) + +const _OPERATION_PROVIDERS = AbstractOperationProvider[] +const _OPERATION_PROVIDER_LOCK = ReentrantLock() + +registered_providers() = lock(_OPERATION_PROVIDER_LOCK) do + copy(_OPERATION_PROVIDERS) +end +clear_provider_registry!() = lock(_OPERATION_PROVIDER_LOCK) do + empty!(_OPERATION_PROVIDERS) +end + +function register_provider!(provider::AbstractOperationProvider) + id = provider_id(provider) + isempty(provider_capabilities(provider)) && throw(ArgumentError("provider must claim at least one operation")) + lock(_OPERATION_PROVIDER_LOCK) do + any(existing -> provider_id(existing) == id, _OPERATION_PROVIDERS) && + throw(ArgumentError("duplicate operation provider id: $id")) + push!(_OPERATION_PROVIDERS, provider) + end + provider +end + +function _compatible(claim::CapabilityEvidence, request::OperationRequest) + claim.operation == request.operation || return false + claim.operation_version.major == request.version.major || return false + claim.operation_version.minor >= request.version.minor || return false + request.lane in claim.lanes || return false + _SUPPORT_RANK[claim.support] >= _SUPPORT_RANK[request.minimum_support] || return false + _DETERMINISM_RANK[claim.determinism] >= _DETERMINISM_RANK[request.minimum_determinism] || return false + request.lane === :authoritative && claim.determinism !== :canonical_exact && return false + claim.implementation === :simulation && !request.allow_simulation && return false + request.named_provider !== nothing && claim.provider_id != request.named_provider && return false + request.fallback === :require_deterministic_equivalent && claim.determinism !== :canonical_exact && return false + request.fallback === :allow_reference && claim.implementation !== :reference && return false + true +end + +function _preference(claim::CapabilityEvidence) + kind = Dict(:hardware => 5, :native => 4, :remote => 3, :reference => 2, :simulation => 1)[claim.implementation] + (kind, _SUPPORT_RANK[claim.support], _DETERMINISM_RANK[claim.determinism]) +end + +"""Select one provider deterministically. Registration order never breaks ties.""" +function plan_operation(request::OperationRequest) + candidates = Tuple{AbstractOperationProvider,CapabilityEvidence}[] + lock(_OPERATION_PROVIDER_LOCK) do + for provider in _OPERATION_PROVIDERS, claim in provider_capabilities(provider) + _compatible(claim, request) && push!(candidates, (provider, claim)) + end + end + isempty(candidates) && throw(ErrorException("no compatible provider for $(request.operation)")) + sort!(candidates; by=entry -> begin + preference = _preference(entry[2]) + (-preference[1], -preference[2], -preference[3], entry[2].provider_id) + end) + candidates[1] +end + +"""Execute exactly the planned provider. A runtime failure is never a fallback signal.""" +function execute_operation(request::OperationRequest, args...) + provider, claim = plan_operation(request) + value = _execute_provider(provider, request, args...) + evidence = ExecutionEvidence(claim.provider_id, claim.provider_version, + claim.operation, request.version, request.lane, claim.support, + claim.determinism, claim.implementation) + value, evidence +end + +# Enaction v1 C-compatible structs. Idris2 remains their authority; these +# assertions make drift fail at Julia load rather than corrupting a call. +struct _EnactionRequest + abi_major::UInt16; abi_minor::UInt16; operation_major::UInt16; operation_minor::UInt16 + operation::UInt32; lane::UInt32; minimum_support::UInt32; minimum_determinism::UInt32 + layout::UInt32; reserved::UInt32; dim0::UInt64; dim1::UInt64; dim2::UInt64 +end +struct _EnactionBufferIn + data::Ptr{Float32}; len::UInt64 +end +struct _EnactionBufferOut + data::Ptr{Float32}; len::UInt64 +end +struct _EnactionCapability + abi_major::UInt16; abi_minor::UInt16; operation_major::UInt16; operation_minor::UInt16 + operation::UInt32; support::UInt32; determinism::UInt32; backend_id::UInt32 + device_class::UInt32; flags::UInt32 +end +struct _EnactionEvidence + abi_major::UInt16; abi_minor::UInt16; operation_major::UInt16; operation_minor::UInt16 + operation::UInt32; backend_id::UInt32; support::UInt32; determinism::UInt32 +end + +sizeof(_EnactionRequest) == 56 || error("Enaction Request ABI drift") +sizeof(_EnactionBufferIn) == 16 || error("Enaction buffer ABI drift") +sizeof(_EnactionCapability) == 32 || error("Enaction Capability ABI drift") +sizeof(_EnactionEvidence) == 24 || error("Enaction Evidence ABI drift") + +const _OP_CODE = Dict( + "enaction.tensor.f32.relu" => UInt32(3), "enaction.tensor.f32.relu6" => UInt32(4), + "enaction.tensor.f32.matmul" => UInt32(5), "enaction.tensor.f32.add" => UInt32(6), + "enaction.tensor.f32.mul" => UInt32(7), +) +const _CODE_OP = Dict(value => key for (key, value) in _OP_CODE) +const _SUPPORT_CODE = Dict(key => UInt32(value) for (key, value) in _SUPPORT_RANK) +const _DETERMINISM_CODE = Dict(key => UInt32(value) for (key, value) in _DETERMINISM_RANK) + +mutable struct EnactionZigProvider <: AbstractOperationProvider + id::String + version::VersionNumber + path::String + handle::Ptr{Cvoid} + claims::Vector{CapabilityEvidence} + unary::Ptr{Cvoid} + binary::Ptr{Cvoid} +end + +provider_id(provider::EnactionZigProvider) = provider.id +provider_capabilities(provider::EnactionZigProvider) = copy(provider.claims) + +function EnactionZigProvider(path::AbstractString) + isfile(path) || throw(ArgumentError("Enaction Zig library not found: $path")) + handle = Libdl.dlopen(path) + abi_version = ccall(Libdl.dlsym(handle, :enaction_accel_abi_version), UInt32, ()) + abi_version == 0x00010000 || throw(ErrorException("unsupported Enaction accelerator ABI: $abi_version")) + count = ccall(Libdl.dlsym(handle, :enaction_accel_capability_count), UInt32, ()) + at = Libdl.dlsym(handle, :enaction_accel_capability_at) + claims = CapabilityEvidence[] + for index in UInt32(0):(count - UInt32(1)) + raw = Ref{_EnactionCapability}() + status = ccall(at, UInt32, (UInt32, Ref{_EnactionCapability}), index, raw) + status == 0 || throw(ErrorException("capability query failed with status $status")) + raw[].abi_major == 1 && raw[].abi_minor == 0 && + raw[].operation_major == 1 && raw[].operation_minor == 0 && + raw[].backend_id == 1 && raw[].device_class == 1 || + throw(ErrorException("invalid Enaction capability evidence at index $index")) + operation = get(_CODE_OP, raw[].operation, nothing) + operation === nothing && continue # fixed-i32 uses a different Julia buffer surface + support = Symbol(first(key for (key, value) in _SUPPORT_CODE if value == raw[].support)) + determinism = Symbol(first(key for (key, value) in _DETERMINISM_CODE if value == raw[].determinism)) + push!(claims, CapabilityEvidence("enaction.cpu.zig.scalar", v"1.0.0", operation, v"1.0.0"; + lanes=(:advisory,), support, determinism, implementation=:native, + device_class=:cpu, conformance_digest=nothing)) + end + EnactionZigProvider("enaction.cpu.zig.scalar", v"1.0.0", String(path), handle, claims, + Libdl.dlsym(handle, :enaction_accel_execute_f32), + Libdl.dlsym(handle, :enaction_accel_execute_f32_binary)) +end + +function _native_layout(request::OperationRequest) + if request.operation == "enaction.tensor.f32.matmul" + all(key -> haskey(request.layout, key), (:m, :k, :n)) || throw(ArgumentError("matmul layout needs m, k and n")) + UInt32(2), UInt64(request.layout.m), UInt64(request.layout.k), UInt64(request.layout.n) + else + haskey(request.layout, :len) || throw(ArgumentError("vector layout needs len")) + UInt32(3), UInt64(request.layout.len), UInt64(0), UInt64(0) + end +end + +function _execute_provider(provider::EnactionZigProvider, request::OperationRequest, args...) + code = get(_OP_CODE, request.operation, nothing) + code === nothing && throw(ArgumentError("unsupported native operation: $(request.operation)")) + layout, dim0, dim1, dim2 = _native_layout(request) + raw_request = Ref(_EnactionRequest(1, 0, UInt16(request.version.major), UInt16(request.version.minor), + code, 2, _SUPPORT_CODE[request.minimum_support], _DETERMINISM_CODE[request.minimum_determinism], + layout, 0, dim0, dim1, dim2)) + evidence = Ref{_EnactionEvidence}() + inputs = if request.operation == "enaction.tensor.f32.matmul" + map(value -> vec(permutedims(Float32.(value))), args) + else + map(value -> vec(Float32.(value)), args) + end + expected = request.operation == "enaction.tensor.f32.matmul" ? Int(dim0 * dim2) : Int(dim0) + output = Vector{Float32}(undef, expected) + output_buffer = Ref(_EnactionBufferOut(pointer(output), UInt64(length(output)))) + status = GC.@preserve inputs output begin + buffers = map(value -> Ref(_EnactionBufferIn(pointer(value), UInt64(length(value)))), inputs) + if length(buffers) == 1 + ccall(provider.unary, UInt32, + (Ref{_EnactionRequest}, Ref{_EnactionBufferIn}, Ref{_EnactionBufferOut}, Ref{_EnactionEvidence}), + raw_request, buffers[1], output_buffer, evidence) + elseif length(buffers) == 2 + ccall(provider.binary, UInt32, + (Ref{_EnactionRequest}, Ref{_EnactionBufferIn}, Ref{_EnactionBufferIn}, Ref{_EnactionBufferOut}, Ref{_EnactionEvidence}), + raw_request, buffers[1], buffers[2], output_buffer, evidence) + else + throw(ArgumentError("native tensor operations take one or two inputs")) + end + end + status == 0 || throw(ErrorException("Enaction Zig operation failed with ABI status $status")) + raw_evidence = evidence[] + raw_evidence.abi_major == 1 && raw_evidence.abi_minor == 0 && + raw_evidence.operation_major == request.version.major && + raw_evidence.operation_minor == request.version.minor && + raw_evidence.operation == code && raw_evidence.backend_id == 1 && + raw_evidence.support >= _SUPPORT_CODE[request.minimum_support] && + raw_evidence.determinism >= _DETERMINISM_CODE[request.minimum_determinism] || + throw(ErrorException("invalid Enaction execution evidence")) + request.operation == "enaction.tensor.f32.matmul" ? reshape(output, Int(dim2), Int(dim0))' |> Matrix : output +end diff --git a/test/runtests.jl b/test/runtests.jl index 8ad0756..c7d83a8 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -288,6 +288,81 @@ using AcceleratorGate @test is_specialized(JuliaBackend(), :matmul) == false end + @testset "Operation-first provider admission" begin + clear_provider_registry!() + simulation_claim = CapabilityEvidence( + "test.simulated.tpu", v"1.0.0", "enaction.tensor.f32.mul", v"1.0.0"; + lanes=(:advisory,), support=:conformant, + determinism=:tolerance_bounded, implementation=:simulation, + device_class=:tpu, + ) + simulation = FunctionProvider("test.simulated.tpu", v"1.0.0", [simulation_claim]) do _, left, right + left .* right + end + register_provider!(simulation) + + refused = OperationRequest("enaction.tensor.f32.mul"; + layout=(len=2,), allow_simulation=false) + @test_throws ErrorException plan_operation(refused) + + admitted = OperationRequest("enaction.tensor.f32.mul"; + layout=(len=2,), allow_simulation=true) + value, evidence = execute_operation(admitted, Float32[2, 3], Float32[4, 5]) + @test value == Float32[8, 15] + @test evidence.provider_id == "test.simulated.tpu" + @test evidence.implementation == :simulation + @test evidence.lane == :advisory + + @test_throws ArgumentError CapabilityEvidence( + "bad.tpu", v"1.0.0", "enaction.tensor.f32.mul", v"1.0.0"; + lanes=(:authoritative,), determinism=:tolerance_bounded, + ) + @test_throws ArgumentError register_provider!(simulation) + clear_provider_registry!() + end + + @testset "Runtime failure never silently retries" begin + clear_provider_registry!() + claim(id, implementation) = CapabilityEvidence( + id, v"1.0.0", "enaction.tensor.f32.add", v"1.0.0"; + lanes=(:advisory,), support=:resilient, + determinism=:tolerance_bounded, implementation, + ) + failing = FunctionProvider("a.hardware", v"1.0.0", [claim("a.hardware", :hardware)]) do _, _... + error("planted provider failure") + end + reference = FunctionProvider("z.reference", v"1.0.0", [claim("z.reference", :reference)]) do _, left, right + left .+ right + end + register_provider!(reference) + register_provider!(failing) + request = OperationRequest("enaction.tensor.f32.add"; layout=(len=1,)) + @test_throws ErrorException execute_operation(request, Float32[1], Float32[2]) + clear_provider_registry!() + end + + if haskey(ENV, "ENACTION_ACCELERATOR_LIB") + @testset "Enaction pure-Zig provider" begin + clear_provider_registry!() + provider = EnactionZigProvider(ENV["ENACTION_ACCELERATOR_LIB"]) + register_provider!(provider) + @test length(provider_capabilities(provider)) == 5 + + request = OperationRequest("enaction.tensor.f32.matmul"; + layout=(m=2, k=3, n=2), minimum_support=:resilient) + output, evidence = execute_operation(request, + Float32[1 2 3; 4 5 6], Float32[7 8; 9 10; 11 12]) + @test output == Float32[58 64; 139 154] + @test evidence.provider_id == "enaction.cpu.zig.scalar" + @test evidence.implementation == :native + + overflow = OperationRequest("enaction.tensor.f32.mul"; + layout=(len=1,), minimum_support=:resilient) + @test_throws ErrorException execute_operation(overflow, Float32[floatmax(Float32)], Float32[2]) + clear_provider_registry!() + end + end + # ======================================================================== # Platform Detection Tests # ======================================================================== From 5bc13dc0af32e7b72c88eac97f0f2f0a8e4379da Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 9 Aug 2026 07:17:44 +0100 Subject: [PATCH 08/14] docs: add BerryWiki coprocessor notebook --- .machine_readable/6a2/STATE.a2ml | 8 ++++++++ docs/berrywiki/ABI.md | 18 ++++++++++++++++++ docs/berrywiki/Architecture.md | 18 ++++++++++++++++++ docs/berrywiki/Axiom-Kernels.md | 18 ++++++++++++++++++ docs/berrywiki/Backends.md | 18 ++++++++++++++++++ docs/berrywiki/Evidence.md | 18 ++++++++++++++++++ docs/berrywiki/Home.md | 19 +++++++++++++++++++ docs/berrywiki/Kernels.md | 18 ++++++++++++++++++ docs/berrywiki/Machine-Index.md | 18 ++++++++++++++++++ docs/berrywiki/Operations.md | 18 ++++++++++++++++++ docs/berrywiki/Performance.md | 18 ++++++++++++++++++ docs/berrywiki/Roadmap.md | 18 ++++++++++++++++++ docs/berrywiki/Runtime.md | 18 ++++++++++++++++++ docs/berrywiki/Security.md | 18 ++++++++++++++++++ docs/berrywiki/Simulation.md | 18 ++++++++++++++++++ docs/berrywiki/Testing.md | 18 ++++++++++++++++++ docs/berrywiki/UMS-Integration.md | 18 ++++++++++++++++++ docs/berrywiki/_Sidebar.md | 18 ++++++++++++++++++ 18 files changed, 315 insertions(+) create mode 100644 docs/berrywiki/ABI.md create mode 100644 docs/berrywiki/Architecture.md create mode 100644 docs/berrywiki/Axiom-Kernels.md create mode 100644 docs/berrywiki/Backends.md create mode 100644 docs/berrywiki/Evidence.md create mode 100644 docs/berrywiki/Home.md create mode 100644 docs/berrywiki/Kernels.md create mode 100644 docs/berrywiki/Machine-Index.md create mode 100644 docs/berrywiki/Operations.md create mode 100644 docs/berrywiki/Performance.md create mode 100644 docs/berrywiki/Roadmap.md create mode 100644 docs/berrywiki/Runtime.md create mode 100644 docs/berrywiki/Security.md create mode 100644 docs/berrywiki/Simulation.md create mode 100644 docs/berrywiki/Testing.md create mode 100644 docs/berrywiki/UMS-Integration.md create mode 100644 docs/berrywiki/_Sidebar.md diff --git a/.machine_readable/6a2/STATE.a2ml b/.machine_readable/6a2/STATE.a2ml index e09f348..1e7c42c 100644 --- a/.machine_readable/6a2/STATE.a2ml +++ b/.machine_readable/6a2/STATE.a2ml @@ -7,8 +7,16 @@ project = "AcceleratorGate.jl" version = "0.1.0" last-updated = "2026-03-15" status = "active" +wiki = "docs/berrywiki/" +wiki-pages = 16 +wiki-tool = "metadatastician/berrywiki" [project-context] name = "AcceleratorGate.jl" completion-percentage = 5 phase = "alpha" + +[coprocessor-documentation] +human-index = "docs/berrywiki/Home.md" +machine-index = "docs/berrywiki/Machine-Index.md" +scope = "provider admission, deterministic planning, execution evidence, and shared Zig ABI" diff --git a/docs/berrywiki/ABI.md b/docs/berrywiki/ABI.md new file mode 100644 index 0000000..d759058 --- /dev/null +++ b/docs/berrywiki/ABI.md @@ -0,0 +1,18 @@ + + +# ABI + +Stable Idris2-facing and Zig FFI layout rules. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Architecture.md b/docs/berrywiki/Architecture.md new file mode 100644 index 0000000..62ebd2e --- /dev/null +++ b/docs/berrywiki/Architecture.md @@ -0,0 +1,18 @@ + + +# Architecture + +Boundaries, ownership, and data flow. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Axiom-Kernels.md b/docs/berrywiki/Axiom-Kernels.md new file mode 100644 index 0000000..1787574 --- /dev/null +++ b/docs/berrywiki/Axiom-Kernels.md @@ -0,0 +1,18 @@ + + +# Axiom-Kernels + +Axiom-derived pointwise, binary, and attention coverage. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Backends.md b/docs/berrywiki/Backends.md new file mode 100644 index 0000000..f441343 --- /dev/null +++ b/docs/berrywiki/Backends.md @@ -0,0 +1,18 @@ + + +# Backends + +Backend/provider registration and selection. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Evidence.md b/docs/berrywiki/Evidence.md new file mode 100644 index 0000000..b4741e9 --- /dev/null +++ b/docs/berrywiki/Evidence.md @@ -0,0 +1,18 @@ + + +# Evidence + +Capability and execution evidence requirements. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Home.md b/docs/berrywiki/Home.md new file mode 100644 index 0000000..2984779 --- /dev/null +++ b/docs/berrywiki/Home.md @@ -0,0 +1,19 @@ + + +# AcceleratorGate.jl + +Julia operation-first admission and evidence control plane. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +This BerryWiki notebook is the human-facing index; the repository's machine-readable state file is authoritative for automation. + diff --git a/docs/berrywiki/Kernels.md b/docs/berrywiki/Kernels.md new file mode 100644 index 0000000..10d1c9d --- /dev/null +++ b/docs/berrywiki/Kernels.md @@ -0,0 +1,18 @@ + + +# Kernels + +Kernel families, layouts, and numerical contracts. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Machine-Index.md b/docs/berrywiki/Machine-Index.md new file mode 100644 index 0000000..650cba7 --- /dev/null +++ b/docs/berrywiki/Machine-Index.md @@ -0,0 +1,18 @@ + + +# Machine-Index + +Machine-readable inventory and automation entry point. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Operations.md b/docs/berrywiki/Operations.md new file mode 100644 index 0000000..3d302ba --- /dev/null +++ b/docs/berrywiki/Operations.md @@ -0,0 +1,18 @@ + + +# Operations + +Canonical operation names and request semantics. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Performance.md b/docs/berrywiki/Performance.md new file mode 100644 index 0000000..0a25477 --- /dev/null +++ b/docs/berrywiki/Performance.md @@ -0,0 +1,18 @@ + + +# Performance + +Benchmarking, determinism, and tuning guidance. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Roadmap.md b/docs/berrywiki/Roadmap.md new file mode 100644 index 0000000..b0f0a31 --- /dev/null +++ b/docs/berrywiki/Roadmap.md @@ -0,0 +1,18 @@ + + +# Roadmap + +Near-term implementation and admission milestones. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Runtime.md b/docs/berrywiki/Runtime.md new file mode 100644 index 0000000..600f00f --- /dev/null +++ b/docs/berrywiki/Runtime.md @@ -0,0 +1,18 @@ + + +# Runtime + +Lifecycle, loading, and failure terminality. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Security.md b/docs/berrywiki/Security.md new file mode 100644 index 0000000..b65d8f2 --- /dev/null +++ b/docs/berrywiki/Security.md @@ -0,0 +1,18 @@ + + +# Security + +Trust boundaries, validation, and unsafe inputs. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Simulation.md b/docs/berrywiki/Simulation.md new file mode 100644 index 0000000..7628d31 --- /dev/null +++ b/docs/berrywiki/Simulation.md @@ -0,0 +1,18 @@ + + +# Simulation + +Rules for simulation, refusal, and conformance claims. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/Testing.md b/docs/berrywiki/Testing.md new file mode 100644 index 0000000..9d751f0 --- /dev/null +++ b/docs/berrywiki/Testing.md @@ -0,0 +1,18 @@ + + +# Testing + +Local tests, integration tests, and acceptance gates. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/UMS-Integration.md b/docs/berrywiki/UMS-Integration.md new file mode 100644 index 0000000..7059d79 --- /dev/null +++ b/docs/berrywiki/UMS-Integration.md @@ -0,0 +1,18 @@ + + +# UMS-Integration + +How the universal model space contract is consumed. + +AcceleratorGate is the Julia-side policy plane: it chooses providers, records evidence, and refuses unsupported or unauthorised simulation. + +See [[Home]] for the project boundary and the repository machine-readable state for exact fields. diff --git a/docs/berrywiki/_Sidebar.md b/docs/berrywiki/_Sidebar.md new file mode 100644 index 0000000..a2eadce --- /dev/null +++ b/docs/berrywiki/_Sidebar.md @@ -0,0 +1,18 @@ +# Notebook + +- [AcceleratorGate.jl](Home) +- [Architecture](Architecture) +- [Operations](Operations) +- [Backends](Backends) +- [Kernels](Kernels) +- [Evidence](Evidence) +- [ABI](ABI) +- [UMS-Integration](UMS-Integration) +- [Simulation](Simulation) +- [Axiom-Kernels](Axiom-Kernels) +- [Runtime](Runtime) +- [Testing](Testing) +- [Security](Security) +- [Performance](Performance) +- [Roadmap](Roadmap) +- [Machine-Index](Machine-Index) From 2fce2ce37bb48282582edf1cf9652ff212ffc1ca Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 9 Aug 2026 07:50:30 +0100 Subject: [PATCH 09/14] chore: refresh governance metadata --- GOVERNANCE.md | 2 +- MAINTAINERS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GOVERNANCE.md b/GOVERNANCE.md index e27364c..3d41c87 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -57,4 +57,4 @@ By submitting a pull request, you agree to license your contributions accordingl --- -*Last updated: 2026-07-18* +*Last updated: 2026-08-09* diff --git a/MAINTAINERS b/MAINTAINERS index 37f6411..c0b34bf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -40,4 +40,4 @@ To become a maintainer: --- -*Last updated: 2026-07-18* +*Last updated: 2026-08-09* From a94cd1be5bfce702247d7aefb7fd23d2c13cdfcb Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 9 Aug 2026 08:13:26 +0100 Subject: [PATCH 10/14] ci: align Julia action and cache pins --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4d2834..a686cee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,9 +25,9 @@ jobs: os: macos-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - uses: julia-actions/setup-julia@4c0cb0fce8556fdb04a90347310e5db8b1f98fb9 # v2 + - uses: julia-actions/setup-julia@fa02766e078afaaf09b14210362cee14137e6a32 # v3.0.2 with: version: ${{ matrix.julia-version }} - - uses: julia-actions/cache@e33b4bfa0ea7cd9caedd7cb82b0e36956ef40285 # v2 + - uses: julia-actions/cache@a45e8fa8be21c18a06b7177052533149e61e9b38 # v3.1.0 - name: Install, build, test run: julia --project=. -e 'using Pkg; Pkg.instantiate(); Pkg.build(); Pkg.test()' From 4c9fb635d587da4f5e8f92a871a9090ca00b3cc9 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:49:28 +0100 Subject: [PATCH 11/14] fix: record Libdl in manifest --- Manifest.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Manifest.toml b/Manifest.toml index b36722a..caa4de5 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -15,6 +15,10 @@ deps = ["Printf"] uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" version = "1.11.0" +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" +version = "1.11.0" + [[deps.Printf]] deps = ["Unicode"] uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" From 58681caca35607cbdf4d3e337f986caac979575f Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 13 Aug 2026 01:48:29 +0100 Subject: [PATCH 12/14] fix(ci): remove erroneous squisher-corpus guix.scm placeholder Part of estate-wide standards#426 remediation - cleanup. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe --- guix.scm | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 guix.scm diff --git a/guix.scm b/guix.scm deleted file mode 100644 index c6dd7be..0000000 --- a/guix.scm +++ /dev/null @@ -1,18 +0,0 @@ -; SPDX-License-Identifier: MPL-2.0 -;; guix.scm — GNU Guix package definition for squisher-corpus -;; Usage: guix shell -f guix.scm - -(use-modules (guix packages) - (guix build-system gnu) - (guix licenses)) - -(package - (name "squisher-corpus") - (version "0.1.0") - (source #f) - (build-system gnu-build-system) - (synopsis "squisher-corpus") - (description "squisher-corpus — part of the hyperpolymath ecosystem.") - (home-page "https://github.com/hyperpolymath/squisher-corpus") - (license ((@@ (guix licenses) license) "PMPL-1.0-or-later" - "https://github.com/hyperpolymath/palimpsest-license"))) From 1cc05405d6d3152572381d36abd4fd59b00e2521 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 13 Aug 2026 01:48:29 +0100 Subject: [PATCH 13/14] fix(ci): remove erroneous squisher-corpus guix.scm placeholder Part of estate-wide standards#426 remediation - cleanup. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe --- guix.scm | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 guix.scm diff --git a/guix.scm b/guix.scm deleted file mode 100644 index c6dd7be..0000000 --- a/guix.scm +++ /dev/null @@ -1,18 +0,0 @@ -; SPDX-License-Identifier: MPL-2.0 -;; guix.scm — GNU Guix package definition for squisher-corpus -;; Usage: guix shell -f guix.scm - -(use-modules (guix packages) - (guix build-system gnu) - (guix licenses)) - -(package - (name "squisher-corpus") - (version "0.1.0") - (source #f) - (build-system gnu-build-system) - (synopsis "squisher-corpus") - (description "squisher-corpus — part of the hyperpolymath ecosystem.") - (home-page "https://github.com/hyperpolymath/squisher-corpus") - (license ((@@ (guix licenses) license) "PMPL-1.0-or-later" - "https://github.com/hyperpolymath/palimpsest-license"))) From baa230e572426bc34c33767afc892ded11c7847a Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 17 Aug 2026 21:35:47 +0100 Subject: [PATCH 14/14] chore: sync estate-wide funding and config updates - Update .github/funding.yml with hyperpolymath platforms - Add FUNDING and PROOF-PROGRESS.adoc files - Update .gitignore Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe --- .github/funding.yml | 20 +++++++-- .gitignore | 2 +- FUNDING | 34 ++++++++++++++ PROOF-PROGRESS.adoc | 105 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 FUNDING create mode 100644 PROOF-PROGRESS.adoc diff --git a/.github/funding.yml b/.github/funding.yml index e4f7c07..dc1b7fa 100644 --- a/.github/funding.yml +++ b/.github/funding.yml @@ -1,4 +1,18 @@ -# Funding Configuration -# See: https://docs.github.com/en/repositories/managing-your-repositorys-custom-fields/displaying-a-sponsor-button-in-your-repository +# SPDX-License-Identifier: MPL-2.0 for code +# SPDX-License-Identifier: CC-BY-SA-4.0 for documentation +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell -github: metadatastician +# These are supported funding model platforms + +buy_me_a_coffee: jonathan.jewell +community_bridge: jonathan-jewell +github: hyperpolymath +indieweb: +issuehunt: hyperpolymath +ko_fi: hyperpolymath +lfx_crowdfunding: hyperpolymath +liberapay: hyperpolymath +open_collective: jonathan-jewell +patreon: cc_studio +polar: hyperpolymath +thanks_dev: hyperpolymath diff --git a/.gitignore b/.gitignore index 36a0887..4c6aa62 100644 --- a/.gitignore +++ b/.gitignore @@ -39,7 +39,7 @@ erl_crash.dump *.jl.mem /Manifest.toml -# ReScript +# /lib/bs/ /.bsb.lock diff --git a/FUNDING b/FUNDING new file mode 100644 index 0000000..7e58d67 --- /dev/null +++ b/FUNDING @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MPL-2.0 for code +// SPDX-License-Identifier: CC-BY-SA-4.0 for documentation +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell + += Funding +:toc: macro +:toclevels: 2 + +This document lists the supported funding platforms for the hyperpolymath and metadatastician estates. + +== Supported Funding Platforms + +[cols="1,1",options="header"] +|=== +| Platform | Username +| Buy Me a Coffee | jonathan.jewell +| Community Bridge | jonathan-jewell +| GitHub Sponsors | hyperpolymath +| IndieWeb | +| IssueHunt | hyperpolymath +| Ko-fi | hyperpolymath +| LFX Crowdfunding | hyperpolymath +| LiberaPay | hyperpolymath +| Open Collective | jonathan-jewell +| Patreon | cc_studio +| Polar | hyperpolymath +| Thanks Dev | hyperpolymath +|=== + +== Usage + +These platforms provide financial support mechanisms for the projects within the hyperpolymath and metadatastician estates. Contributions through any of these platforms help sustain development, maintenance, and governance of the open source projects. + +For more information about contributing or sponsoring specific projects, please refer to the project's README file or contact the maintainers directly. diff --git a/PROOF-PROGRESS.adoc b/PROOF-PROGRESS.adoc new file mode 100644 index 0000000..7a4c65b --- /dev/null +++ b/PROOF-PROGRESS.adoc @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell +// +// Proof Progress Snapshot — AcceleratorGate.jl +// Generated: 2026-08-14 + += AcceleratorGate.jl — Proof/Verification Guarantee Progress Snapshot +:toc: +:icons: font + +This document provides an indicative state of progress on formal guarantees for +the AcceleratorGate.jl Julia package as of 2026-08-14. It consolidates information from: + +- `README.md` — Project overview and backend-selection claims +- `src/` — Core type hierarchy and selection logic +- `test/` — Test suite + +== Headline Status + +[cols="1,2,3",options="header"] +|=== +| Component | Status | Details + +| Backend-selection layer | ✅ COMPLETE | Type hierarchy for compute backends + +| JuliaBackend | ✅ COMPLETE | CPU/backend type + +| CUDABackend | ✅ COMPLETE | NVIDIA CUDA backend type + +| ROCmBackend | ✅ COMPLETE | AMD ROCm backend type + +| MetalBackend | ✅ COMPLETE | Apple Metal backend type + +| TPUBackend | ✅ COMPLETE | Tensor Processing Unit backend type + +| NPUBackend | ✅ COMPLETE | Neural Processing Unit backend type + +| FPGABackend | ✅ COMPLETE | Field-Programmable Gate Array backend type + +| QPUBackend | ✅ COMPLETE | Quantum Processing Unit backend type + +| DSPBackend | ✅ COMPLETE | Digital Signal Processor backend type + +| Environment detection | ✅ COMPLETE | Availability detection for each backend + +| Platform probe | ✅ COMPLETE | Platform capability detection + +| select_backend | ✅ COMPLETE | Heuristic backend selection API + +| estimate_cost | ✅ COMPLETE | Cost estimation API + +| fits_on_device | ✅ COMPLETE | Memory/fit checking API + +| Kernel execution | ❌ NOT IMPLEMENTED | Does NOT execute GPU/accelerator computation + +| Vendor runtime linking | ❌ NOT IMPLEMENTED | Links no vendor runtimes (CUDA.jl, AMDGPU.jl, etc.) + +| Kernel implementation | ❌ NOT IMPLEMENTED | Contains no kernels +|=== + +**Overall:** AcceleratorGate.jl provides a **small, dependency-light backend-selection +layer** extracted from Axiom.jl's backend module. It offers a type hierarchy of +compute backends with environment-based availability detection, platform probe, +and heuristic selection API. Crucially, it **does not execute computation** — it +is purely the typing and selection layer. + +== Design Philosophy + +From README.md: AcceleratorGate.jl is deliberately narrower than KernelAbstractions.jl, +GPUArrays.jl, Adapt.jl. It is purely typing and selection with no compute and minimal +deps. It helps host packages decide and describe backends uniformly. + +**Does NOT:** +- Execute GPU/accelerator computation +- Contain kernels +- Link vendor runtimes (CUDA.jl, AMDGPU.jl, Metal.jl, oneAPI.jl) + +== Backend Types + +[cols="1,2,1"] +|=== +| Type | Description | Status +| JuliaBackend | CPU | ✅ +| CUDABackend | NVIDIA CUDA | ✅ +| ROCmBackend | AMD ROCm | ✅ +| MetalBackend | Apple Metal | ✅ +| TPUBackend | Google TPU | ✅ +| NPUBackend | Neural Processing Unit | ✅ +| FPGABackend | FPGA | ✅ +| QPUBackend | Quantum Processing Unit | ✅ +| DSPBackend | Digital Signal Processor | ✅ +|=== + +== Ecosystem Integration + +Used by: Axiom.jl (extracted from), LowLevel.jl, QuantumCircuit.jl + +== Document Information + +[cols="1,2"] +|=== +| Generated | 2026-08-14 | +| Author | Mistral Vibe | +| Status | Complete | +|===