20 KiB
OPREG/PEL1-KERNEL — Kernel Operation Registry for PEL/1
Status: Approved Owner: Niklas Rydberg Version: 0.1.1 SoT: Yes Last Updated: 2025-11-16 Linked Phase Pack: N/A Tags: [registry, execution]
Document ID: OPREG/PEL1-KERNEL
Layer: L1 Profile (Operation Registry for PEL/1-CORE + PEL/PROGRAM-DAG/1)
Depends on (normative):
ASL/1-CORE v0.3.x—Artifact,TypeTag,Reference,HashIdPEL/1-CORE v0.1.x— primitive execution layer corePEL/PROGRAM-DAG/1 v0.2.x— DAG scheme for PELHASH/ASL1 v0.2.x— ASL1 hash family (forHASH-ASL1-256)
Integrates with (informative):
SUBSTRATE/STACK-OVERVIEW v0.1.xENC/PEL-PROGRAM-DAG/1(canonical encoding of Program)PEL/TRACE-DAG/1(optional trace profile)- Higher-level operation registries (domain-specific ops)
© 2025 Niklas Rydberg.
License
Except where otherwise noted, this document (text and diagrams) is licensed under the Creative Commons Attribution 4.0 International License (CC BY 4.0).
The identifier registries and mapping tables (e.g. TypeTag IDs, HashId assignments, EdgeTypeId tables) are additionally made available under CC0 1.0 Universal (CC0) to enable unrestricted reuse in implementations and derivative specifications.
Code examples in this document are provided under the Apache License 2.0 unless explicitly stated otherwise. Test vectors, where present, are dedicated to the public domain under CC0 1.0.
0. Purpose and Non-Goals
0.1 Purpose
OPREG/PEL1-KERNEL defines a minimal, globally stable set of PEL operations that every “kernel-capable” PEL engine is expected to implement:
-
They operate on ASL/1 Artifacts (bytes + optional type tag).
-
They are used in
PEL/PROGRAM-DAG/1programs asOperationId { name, version }. -
They are pure and deterministic: same inputs → same outputs, independent of engine or environment.
-
They explicitly define:
- Arity (number of inputs),
- Parameter model (logical Params value),
- Output shape (number and form of outputs),
- Runtime error conditions and associated
status_codevalues forPEL/PROGRAM-DAG/1.
These operations are intentionally low-level and byte-centric; richer semantics (JSON, typed records, domain-specific logic) belong in separate registries.
0.2 Non-goals
This registry does not define:
- Any storage or transport API (
ASL/1-STORE). - Any encoding of Programs or Params into bytes (
ENC/PEL-PROGRAM-DAG/1, param-encoding profiles). - Any certification or fact semantics (
CIL/1,FER/1,FCT/1). - Provenance graph edges (
TGK/1). - Human-readable diagnostics payloads (see §2.4).
1. Conventions and Context
1.1 Base types
From ASL/1-CORE:
Artifact {
bytes: OctetString
type_tag: optional TypeTag
}
TypeTag {
tag_id: uint32
}
Reference {
hash_id: HashId
digest: OctetString
}
HashId = uint16
From PEL/1-CORE and PEL/PROGRAM-DAG/1 (simplified):
OperationId {
name: string
version: uint32
}
ExecutionStatus = uint8 // e.g. OK, INVALID_PROGRAM, INVALID_INPUTS, RUNTIME_FAILED
ExecutionErrorKind = uint8 // e.g. NONE, PROGRAM, INPUTS, RUNTIME
ExecutionErrorSummary {
kind: ExecutionErrorKind
status_code: uint32
}
DiagnosticEntry {
code: uint32
message: OctetString
}
ExecutionResultValue {
pel1_version : uint16
status : ExecutionStatus
scheme_ref : SchemeRef
summary : ExecutionErrorSummary
diagnostics : list<DiagnosticEntry>
}
PEL/PROGRAM-DAG/1 defines Exec_DAG as:
Exec_DAG(
program: Artifact,
inputs: list<Artifact>,
params: optional Artifact
) -> (outputs: list<Artifact>, result: ExecutionResultValue)
and defines that each Node evaluates an OperationId with a logical interface:
Op(name, version)(
inputs: list<Artifact>,
params: ParamsValue
) -> Ok(list<Artifact>) | Err(status_code: uint32)
The overall ExecutionResultValue.summary.status_code for RUNTIME_FAILED is taken from the status_code returned by the failing operation.
1.2 Status and error mapping
This registry only defines runtime error codes (used when Exec_DAG sets status = RUNTIME_FAILED).
Global outcome statuses:
ExecutionStatus {
OK = 0
INVALID_PROGRAM = 2
INVALID_INPUTS = 3
RUNTIME_FAILED = 4
}
Error summary kind:
ExecutionErrorKind {
NONE = 0
PROGRAM = 1
INPUTS = 2
RUNTIME = 3
}
Mapping (from PEL/PROGRAM-DAG/1):
status = OK⇒kind = NONE,status_code = 0status = INVALID_PROGRAM⇒kind = PROGRAM,status_code = 2status = INVALID_INPUTS⇒kind = INPUTS,status_code = 3status = RUNTIME_FAILED⇒kind = RUNTIME,status_code = op-specific (> 0)
This registry only defines the operation-specific status_code values that may appear when status = RUNTIME_FAILED.
1.3 Kernel status_code layout
For kernel ops we reserve a simple scheme for status_code on runtime failure:
status_code = (kernel_op_code << 16) | error_index
Where:
kernel_op_codeis a 16-bit numeric code assigned per operation in this registry.error_indexis a small (non-zero) 16-bit integer enumerating distinct error causes per op.
This ensures:
- No collision between error codes of different operations.
- Easy offline decoding of
status_codeinto(op, reason).
Concrete kernel_op_code assignments are given in §3.
1.4 Params and encodings
Each operation defines a logical Params type (e.g. SliceParams { offset: u64; length: u64 }).
This registry does not define byte-level encodings of Params; those are defined in a companion profile (e.g. OPREG/PEL1-KERNEL-PARAMS/1). This document is the semantic registry.
Conformance requirements:
-
For each operation, there MUST exist exactly one canonical encoding and decoding for its Params type.
-
All engines claiming to implement the operation MUST use that same encoding and decoding.
-
If Params decoding fails, the operation MUST treat the Node as either:
INVALID_PROGRAM(preferred for static malformations), orRUNTIME_FAILEDwith a specificstatus_code(if the registry so specifies).
For this initial kernel set, we treat Param decoding errors as INVALID_PROGRAM, not as runtime failures.
1.5 Diagnostics
To keep ExecutionResultValue stable and simple, kernel operations:
For kernel operations, the operation semantics MUST always return an empty diagnostics list, and the scheme’s Exec_DAG implementation MUST NOT add additional diagnostics when a failing Node is a kernel op.
Human-readable error information is expected to be carried in:
- separate trace artifacts (
PEL/TRACE-DAG/1), or - external logs and observability systems, not in
ExecutionResultValue.diagnostics.
2. Common Kernel Operation Conventions
All kernel operations in this registry share these properties:
-
Purity and determinism
-
They operate only on:
- the input
Artifact.bytesandArtifact.type_tag, - their decoded Params,
- standard pure functions (e.g. integer arithmetic, hashing as per
HASH/ASL1).
- the input
-
They MUST NOT:
- read clocks or random sources,
- perform network or filesystem I/O,
- depend on global mutable state.
-
-
Type tags
- Unless otherwise stated, operations preserve the input type tag when transforming a single input.
- For operations with multiple inputs, if they require consistent type tags, this is checked at runtime and may yield a runtime error.
- Operations MAY produce Artifacts with
type_tag = Nonefor “raw bytes” outputs.
-
Arity and static vs dynamic errors
- Each operation specifies
min_inputsandmax_inputs. - Violations of these arity constraints are static (depend only on the Program) and MUST be treated as
INVALID_PROGRAM, notRUNTIME_FAILED. - Runtime errors are reserved for data-dependent conditions (e.g. out-of-bounds slice based on actual input length).
- Each operation specifies
-
Success vs failure
-
On success: operation returns
Ok(list<Artifact>), andExec_DAGkeepsstatus = OK(unless a different Node fails later). -
On failure: operation returns
Err(status_code), andExec_DAGstops evaluation and sets:status = RUNTIME_FAILED summary.kind = RUNTIME summary.status_code = status_code diagnostics = []
-
3. Kernel Operation Index
We define four kernel operations:
| Kernel Op Code | OperationId.name | version | Summary |
|---|---|---|---|
0x0001 |
"pel.bytes.concat" |
1 |
Concatenate N artifacts |
0x0002 |
"pel.bytes.slice" |
1 |
Take a byte slice of one artifact |
0x0003 |
"pel.bytes.const" |
1 |
Produce a constant artifact from params |
0x0004 |
"pel.bytes.hash.asl1" |
1 |
Hash an artifact’s bytes with ASL1 |
All operation names are case-sensitive UTF-8 strings.
Each operation’s OperationId is:
OperationId {
name: <as in table>
version: 1
}
kernel_op_code in the status_code formula (§1.3) is the hex code in the first column.
4. Operation Specifications
4.1 pel.bytes.concat v1 (code 0x0001)
OperationId
name = "pel.bytes.concat"
version = 1
kernel_op_code = 0x0001
Intent
Concatenate the byte payloads of N input Artifacts (N ≥ 1) into a single output Artifact. All input type tags MUST be identical (including “no type tag”).
4.1.1 Arity and Params
min_inputs = 1max_inputs = unbounded(any positive number)- Params: none (
Unit)
Static errors (handled as INVALID_PROGRAM):
inputs.length == 0.- Params not decodable as
Unit(i.e. any non-empty Params according to the canonical encoding).
4.1.2 Semantics
Given:
inputs = [A0, A1, ..., A_{n-1}], n >= 1
params = ()
Let:
Ti = Ai.type_tag
Bi = Ai.bytes
-
Type tag consistency check (runtime)
-
If there exist
i, jsuch thatTiandTjare not equal in theASL/1-COREsense (i.e. one is absent and the other present, or both present but with differenttag_id):- Operation returns
Err(status_code = 0x0001_0001).
- Operation returns
-
-
Concatenation
-
Define:
B_out = B0 || B1 || ... || B_{n-1} // byte-wise concatenation T_out = T0 // they are all equal by step 1 -
Output list is a single Artifact
C:C.bytes = B_out C.type_tag = T_out -
Operation returns
Ok([C]).
-
This operation does not impose any explicit limit on the concatenated length; overflow or resource exhaustion is outside the PEL semantic layer.
4.1.3 Runtime error codes
For pel.bytes.concat v1, runtime errors (producing RUNTIME_FAILED) are:
| Name | Condition | status_code |
|---|---|---|
TYPE_TAG_MISMATCH |
Any pair of input type tags differ | 0x0001_0001 |
On any such error:
- Operation returns
Err(status_code)as above. Exec_DAGsetsstatus = RUNTIME_FAILED,summary.status_code = status_code,diagnostics = [].
4.2 pel.bytes.slice v1 (code 0x0002)
OperationId
name = "pel.bytes.slice"
version = 1
kernel_op_code = 0x0002
Intent
Take a contiguous slice from a single input Artifact’s bytes.
4.2.1 Params: SliceParams
Logical Params:
SliceParams {
offset: uint64 // byte offset, 0-based
length: uint64 // number of bytes to include
}
offsetandlengthare non-negative.- Their canonical encoding/decoding is defined in a param-encoding profile; invalid encodings MUST result in
INVALID_PROGRAM.
4.2.2 Arity
min_inputs = 1max_inputs = 1
Arity violations → INVALID_PROGRAM.
4.2.3 Semantics
Given:
inputs = [A]
params = SliceParams { offset, length }
Let:
B = A.bytes // length = L
T = A.type_tag
L = |B|
o = offset
ℓ = length
-
Range check (runtime)
-
If
o > Loro + ℓ > L(with arithmetic in unbounded integers):- Operation returns
Err(status_code = 0x0002_0001).
- Operation returns
-
-
Slicing
-
Define:
B_out = B[o .. o+ℓ] // ℓ bytes starting at index o -
Output Artifact
C:C.bytes = B_out C.type_tag = T -
Operation returns
Ok([C]).
-
Note: o == L and ℓ == 0 is allowed and yields an empty-byte output.
4.2.4 Runtime error codes
For pel.bytes.slice v1:
| Name | Condition | status_code |
|---|---|---|
RANGE_OUT_OF_BOUNDS |
offset > len(bytes) or offset + length > len(bytes) |
0x0002_0001 |
On such error, Exec_DAG sets status = RUNTIME_FAILED, summary.status_code = 0x0002_0001, diagnostics = [].
4.3 pel.bytes.const v1 (code 0x0003)
OperationId
name = "pel.bytes.const"
version = 1
kernel_op_code = 0x0003
Intent
Produce a constant Artifact specified entirely by Params, with no data dependencies. This is a way to embed small literal values directly in a Program.
4.3.1 Params: ConstParams
Logical Params:
ConstParams {
bytes: OctetString // payload bytes
has_tag: bool // whether a type tag is present
tag_id: uint32 optional // only meaningful if has_tag = true
}
Semantics:
-
If
has_tag == false:- Output Artifact has
type_tag = None.
- Output Artifact has
-
If
has_tag == true:- Output Artifact has
type_tag = Some(TypeTag{ tag_id }).
- Output Artifact has
Param encoding/decoding is defined in a param-encoding profile; malformed encodings ⇒ INVALID_PROGRAM.
4.3.2 Arity
min_inputs = 0max_inputs = 0
Any non-empty inputs list is a static error (INVALID_PROGRAM).
4.3.3 Semantics
Given:
inputs = []
params = ConstParams { bytes = B, has_tag, tag_id? }
Then:
-
If
has_tagis false:C.bytes = B C.type_tag = None -
If
has_tagis true:C.bytes = B C.type_tag = Some(TypeTag{ tag_id }) -
Output list is
[C]. -
Operation returns
Ok([C]).
There are no data-dependent runtime errors: this operation always succeeds given valid Params.
4.3.4 Runtime error codes
None.
All failures are static (bad Params encoding, wrong arity) and must be treated as INVALID_PROGRAM.
4.4 pel.bytes.hash.asl1 v1 (code 0x0004)
OperationId
name = "pel.bytes.hash.asl1"
version = 1
kernel_op_code = 0x0004
Intent
Compute an ASL1-family hash (HASH/ASL1) over the raw bytes of a single input Artifact.
This operation is not about ASL/1 identity (which uses ArtifactBytes via ENC/ASL1-CORE), but about hashing arbitrary byte payloads for protocol or application use.
4.4.1 Params: HashParams
Logical Params:
HashParams {
hash_id: HashId // must be a valid ASL1 HashId
}
For this version:
hash_idMUST be0x0001(i.e.HASH-ASL1-256).- Any other
hash_idMUST be treated as a static error ⇒INVALID_PROGRAM.
Rationale: this ensures all conformant engines agree on the algorithm set for this op. Future versions (e.g. pel.bytes.hash.asl1 v2) MAY support additional HashIds.
Param encoding/decoding is defined elsewhere; malformed encodings ⇒ INVALID_PROGRAM.
4.4.2 Arity
min_inputs = 1max_inputs = 1
Arity violations ⇒ INVALID_PROGRAM.
4.4.3 Semantics
Given:
inputs = [A]
params = HashParams { hash_id = 0x0001 }
Let:
B = A.bytes
H = HASH-ASL1-256 // SHA-256 as defined in HASH/ASL1 for HashId 0x0001
Compute:
digest = H(B) // 32-byte digest
Then:
-
Output Artifact
C:C.bytes = digest // exactly 32 bytes C.type_tag = None // raw bytes digest, no type tag -
Output list is
[C]. -
Operation returns
Ok([C]).
There are no data-dependent runtime errors; hashing is assumed total. Any internal errors (e.g. memory failure) are outside PEL semantics.
4.4.4 Runtime error codes
None.
All failures (unsupported hash_id, bad Params, wrong arity) are static and must be treated as INVALID_PROGRAM.
5. Conformance
An engine is OPREG/PEL1-KERNEL–conformant if and only if:
-
Operation availability
- It exposes the four operations defined in §3 with exactly the specified
OperationId { name, version }.
- It exposes the four operations defined in §3 with exactly the specified
-
Arity and Params
-
For each operation, it enforces
min_inputs/max_inputsas specified. -
It implements the defined logical Params types and uses the canonical param encoding/decoding for each.
-
It treats:
- arity violations, and
- invalid or undecodable Params
as
INVALID_PROGRAMperPEL/PROGRAM-DAG/1(i.e.Exec_DAGproducesstatus = INVALID_PROGRAM,summary.status_code = 2).
-
-
Runtime semantics
-
For all supported operations:
- Given the same input Artifacts and Params, all conformant engines produce identical output Artifacts (same
bytes, sametype_tag) and identicalstatus_codeon failure. - Runtime failure conditions (e.g. slice out-of-bounds, type tag mismatch) are detected exactly as specified and mapped to the correct
status_codeusing thekernel_op_code/error_indexscheme.
- Given the same input Artifacts and Params, all conformant engines produce identical output Artifacts (same
-
-
Status and diagnostics mapping
-
When a kernel operation returns
Ok,Exec_DAGMUST NOT changestatusorsummary(beyond normal success semantics). -
When a kernel operation returns
Err(status_code):-
Exec_DAGMUST set:status = RUNTIME_FAILED summary.kind = RUNTIME summary.status_code = status_code diagnostics = [] -
Exec_DAGMUST NOT mutate other fields ofExecutionResultValueexcept as defined inPEL/PROGRAM-DAG/1(e.g. to capture which Node failed, via trace profiles).
-
-
-
Purity
- Kernel operations MUST not perform external I/O or observe environment state; they must behave as pure functions of their inputs and Params.
- Any caching or performance optimizations MUST NOT change observable behavior at the level of
Artifactvalues andstatus_code.
-
Layering
- The engine does not depend on
ASL/1-STORE,TGK/1,CIL/1,FER/1,FCT/1, orOI/1on the PEL core hot path. It may use those layers around PEL, but not as part of the operation semantics.
- The engine does not depend on
6. Change Log (informative)
v0.1.1 (2025-11-15)
-
Removed
pel.bytes.clone/1from the kernel operation index. -
Reassigned
kernel_op_codevalues to remove the0x01gap:pel.bytes.concat/1:0x0002→0x0001(andTYPE_TAG_MISMATCHfrom0x0002_0001→0x0001_0001).pel.bytes.slice/1:0x0003→0x0002(andRANGE_OUT_OF_BOUNDSfrom0x0003_0001→0x0002_0001).pel.bytes.const/1:0x0004→0x0003.pel.bytes.hash.asl1/1:0x0005→0x0004.
-
Updated §3, §4, and §5 to reflect the new kernel op set and codes.
v0.1.0 (2025-11-15)
-
Initial definition of
OPREG/PEL1-KERNELwith five kernel operations:pel.bytes.clone/1pel.bytes.concat/1pel.bytes.slice/1pel.bytes.const/1pel.bytes.hash.asl1/1
-
Established
status_code = (kernel_op_code << 16) | error_indexconvention. -
Restricted
pel.bytes.hash.asl1/1toHashId = 0x0001(HASH-ASL1-256) for cross-implementation determinism. -
Required kernel operations to leave
ExecutionResultValue.diagnosticsempty; richer diagnostics to be handled by trace/overlay profiles.
Document History
- 0.1.1 (2025-11-16): Registered as Tier-1 spec and aligned to the Amduat 2.0 substrate baseline.