1109 lines
34 KiB
Markdown
1109 lines
34 KiB
Markdown
|
|
# ENC/PEL1-RESULT/1 — Canonical Encoding for PEL/1 Execution Results
|
|||
|
|
|
|||
|
|
Status: Approved
|
|||
|
|
Owner: Niklas Rydberg
|
|||
|
|
Version: 0.3.0
|
|||
|
|
SoT: Yes
|
|||
|
|
Last Updated: 2025-11-30
|
|||
|
|
Linked Phase Pack: PH06
|
|||
|
|
Tags: [binary-minimalism, deterministic, execution]
|
|||
|
|
|
|||
|
|
<!-- Source: /amduat/docs/new/enc-pel1-result-1.md | Canonical: /amduat/tier1/enc-pel1-result-1.md -->
|
|||
|
|
|
|||
|
|
**Document ID:** `ENC/PEL1-RESULT/1`
|
|||
|
|
**Profile ID:** `PEL_ENC_EXECUTION_RESULT_V1 = 0x0103`
|
|||
|
|
**Layer:** Scheme Encoding Profile (PEL/1 Surface Result)
|
|||
|
|
|
|||
|
|
**Depends on (normative):**
|
|||
|
|
|
|||
|
|
* `ASL/1-CORE v0.4.x` — value model (`Artifact`, `TypeTag`, `Reference`, `OctetString`)
|
|||
|
|
* `ENC/ASL1-CORE v1.0.x` — canonical encodings for `Artifact` and `Reference`
|
|||
|
|
* `PEL/1-CORE v0.3.x` — `ExecutionResultValue`, `ExecutionStatus`, `ExecutionErrorSummary`, `DiagnosticEntry`
|
|||
|
|
* `PEL/1-SURF v0.2.x` — surface execution result model (`SurfaceExecutionResult` shape)
|
|||
|
|
|
|||
|
|
**Integrates with (informative):**
|
|||
|
|
|
|||
|
|
* `HASH/ASL1 v0.2.x` — ASL1 hash family for result Artifact identity
|
|||
|
|
* `SUBSTRATE/STACK-OVERVIEW v0.4.x` — layering discipline
|
|||
|
|
* `ENC/PEL-PROGRAM-DAG/1 v0.2.x` — list / Utf8 / params encoding conventions
|
|||
|
|
* `ENC/PEL-TRACE-DAG/1 v0.1.x` — `DiagnosticEntry` encoding pattern
|
|||
|
|
* TypeTag registry (for `TYPE_TAG_PEL1_RESULT_1` assignment)
|
|||
|
|
|
|||
|
|
> The Profile ID `PEL_ENC_EXECUTION_RESULT_V1` is a configuration label.
|
|||
|
|
> It is **not** embedded into payloads. Encoders and decoders select this encoding profile by context (scheme descriptor, engine/store configuration), not per value.
|
|||
|
|
|
|||
|
|
© 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. Overview
|
|||
|
|
|
|||
|
|
`ENC/PEL1-RESULT/1` defines the **canonical binary encoding** of the surface-level
|
|||
|
|
execution result structure defined by `PEL/1-SURF` for PEL/1 executions.
|
|||
|
|
|
|||
|
|
Concretely, this profile specifies:
|
|||
|
|
|
|||
|
|
* the binary layout of the PEL/1 surface result value
|
|||
|
|
(`SurfaceExecutionResult`), including:
|
|||
|
|
|
|||
|
|
* `scheme_ref`, `program_ref`,
|
|||
|
|
* `input_refs`, `output_refs`,
|
|||
|
|
* `params_ref`, `store_failure`, `trace_ref`,
|
|||
|
|
* an **inline** encoding of `ExecutionResultValue` from `PEL/1-CORE`;
|
|||
|
|
|
|||
|
|
* how that value is embedded into ASL/1 `Artifact.bytes` as `ResultBytes`;
|
|||
|
|
|
|||
|
|
* the dedicated `TypeTag` used for result Artifacts under this profile.
|
|||
|
|
|
|||
|
|
Result Artifacts are ordinary ASL/1 Artifacts with:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Artifact.type_tag = TYPE_TAG_PEL1_RESULT_1
|
|||
|
|
Artifact.bytes = ResultBytes
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Identity of a result Artifact is then derived from canonical `ArtifactBytes`
|
|||
|
|
(`ENC/ASL1-CORE v1`) and a chosen `HashId` (typically `HASH-ASL1-256`), but hash
|
|||
|
|
algorithm choice is **not** part of this encoding spec.
|
|||
|
|
|
|||
|
|
This profile is:
|
|||
|
|
|
|||
|
|
* **injective** — distinct logical surface result values → distinct `ResultBytes`;
|
|||
|
|
* **stable and deterministic** — same logical value → same bytes across implementations and time;
|
|||
|
|
* **streaming-friendly** — encoders/decoders can operate in a single forward pass.
|
|||
|
|
|
|||
|
|
It does **not** redefine PEL/1 execution semantics or store behavior; it only
|
|||
|
|
fixes the layout of the surface result value described by `PEL/1-SURF`.
|
|||
|
|
|
|||
|
|
> **Encoding vs PEL versioning**
|
|||
|
|
> `pel1_version` fields in this profile encode the PEL/1-CORE major version (`1`),
|
|||
|
|
> **not** the encoding profile version. Encoding version is selected by context
|
|||
|
|
> via `PEL_ENC_EXECUTION_RESULT_V1` and `TYPE_TAG_PEL1_RESULT_1`, not by any
|
|||
|
|
> on-wire version field.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. Scope & Layering
|
|||
|
|
|
|||
|
|
### 1.1 Purpose
|
|||
|
|
|
|||
|
|
This specification defines:
|
|||
|
|
|
|||
|
|
* The **binary layout** of:
|
|||
|
|
|
|||
|
|
* `ResultBytes` — top-level surface result encoding (`SurfaceExecutionResult`);
|
|||
|
|
* `ExecutionResultValueBytes` — inline encoding of `ExecutionResultValue` (`PEL/1-CORE`);
|
|||
|
|
* `DiagnosticEntryBytes` — scheme diagnostics, reusing the pattern from `ENC/PEL-TRACE-DAG/1`;
|
|||
|
|
* `StoreFailureBytes` — store-resolution diagnostics, aligned with `PEL/1-SURF`;
|
|||
|
|
* an internal wrapper for embedded `Reference` values (`EncodedRef`).
|
|||
|
|
|
|||
|
|
* The **field ordering**, integer widths, list framing, and presence flags.
|
|||
|
|
|
|||
|
|
* The **binding** between `ResultBytes` and a dedicated result `TypeTag`.
|
|||
|
|
|
|||
|
|
It does **not** define:
|
|||
|
|
|
|||
|
|
* PEL/1-CORE execution semantics (`Exec_s`) or scheme semantics;
|
|||
|
|
* PEL/1-SURF surface semantics (how stores are wired, which Artifacts *must* be persisted);
|
|||
|
|
* hash algorithms or Reference derivation (from `ASL/1-CORE` + `HASH/ASL1`);
|
|||
|
|
* trace graph semantics or edges (`TGK/1-CORE` and profiles).
|
|||
|
|
|
|||
|
|
### 1.2 Layering constraints
|
|||
|
|
|
|||
|
|
In line with `SUBSTRATE/STACK-OVERVIEW`:
|
|||
|
|
|
|||
|
|
* `ENC/PEL1-RESULT/1` is a **scheme-specific encoding profile** for a PEL/1
|
|||
|
|
surface result structure.
|
|||
|
|
* It MUST NOT redefine:
|
|||
|
|
|
|||
|
|
* `Artifact`, `TypeTag`, `Reference`, `HashId` (`ASL/1-CORE`);
|
|||
|
|
* `ExecutionResultValue`, `ExecutionStatus`, `ExecutionErrorSummary`, `DiagnosticEntry` (`PEL/1-CORE`);
|
|||
|
|
* the logical surface result structure (from `PEL/1-SURF`).
|
|||
|
|
* It is **storage-neutral** and **policy-neutral**:
|
|||
|
|
|
|||
|
|
* it does not talk about particular stores, transports, or policies;
|
|||
|
|
* it does not depend on TGK, CIL, FER, FCT, OI, or any domain profiles.
|
|||
|
|
|
|||
|
|
This profile defines exactly one canonical encoding for PEL/1 surface result values
|
|||
|
|
of the shape described in §3.1.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. Conventions
|
|||
|
|
|
|||
|
|
RFC 2119 terms (**MUST**, **SHOULD**, **MAY**, etc.) are normative.
|
|||
|
|
|
|||
|
|
### 2.1 Integer encodings
|
|||
|
|
|
|||
|
|
All multi-byte integers in this profile are encoded as **big-endian** (network
|
|||
|
|
byte order), as in `ENC/ASL1-CORE` and other PEL encodings:
|
|||
|
|
|
|||
|
|
* `u8` — 1 byte
|
|||
|
|
* `u16` — 2 bytes
|
|||
|
|
* `u32` — 4 bytes
|
|||
|
|
* `u64` — 8 bytes
|
|||
|
|
|
|||
|
|
Only fixed-width integers are used in this specification.
|
|||
|
|
|
|||
|
|
### 2.2 Lists
|
|||
|
|
|
|||
|
|
A list of values of some type `T` is encoded as:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
List<T> =
|
|||
|
|
count (u32)
|
|||
|
|
element_0
|
|||
|
|
element_1
|
|||
|
|
...
|
|||
|
|
element_{count-1}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
* `count` is the number of elements (MAY be zero).
|
|||
|
|
* Elements are encoded in order using the canonical encoding for `T`.
|
|||
|
|
|
|||
|
|
This **u32 length + elements** pattern matches `ENC/PEL-PROGRAM-DAG/1` and
|
|||
|
|
`ENC/PEL-TRACE-DAG/1`.
|
|||
|
|
|
|||
|
|
### 2.3 Utf8String
|
|||
|
|
|
|||
|
|
If this profile needs UTF-8 strings, it uses the same `Utf8String` encoding as
|
|||
|
|
other PEL encodings:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Utf8String =
|
|||
|
|
length (u32)
|
|||
|
|
bytes[0..length-1]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
* `length` is the number of bytes.
|
|||
|
|
* `bytes` MUST be well-formed UTF-8.
|
|||
|
|
* There is no terminator or padding.
|
|||
|
|
|
|||
|
|
The core surface result structure currently does not include free-form text
|
|||
|
|
fields; diagnostics use an opaque blob type instead (§2.4).
|
|||
|
|
|
|||
|
|
### 2.4 Blob32 (Octet blob with 32-bit length)
|
|||
|
|
|
|||
|
|
For diagnostic messages and other opaque payloads, we use:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Blob32 =
|
|||
|
|
length (u32)
|
|||
|
|
bytes[0..length-1]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
* `bytes` is an arbitrary `OctetString`; interpretation is profile- or scheme-specific.
|
|||
|
|
* `length` MAY be zero.
|
|||
|
|
|
|||
|
|
This is the same `Blob32` convention used by `ENC/PEL-TRACE-DAG/1`. It is a
|
|||
|
|
profile-local convenience; it does **not** override the general `OctetString`
|
|||
|
|
encoding from `ENC/ASL1-CORE` (which uses `u64` lengths at the ASL core level).
|
|||
|
|
|
|||
|
|
### 2.5 Embedded Reference (`EncodedRef`)
|
|||
|
|
|
|||
|
|
Within this encoding, `Reference` values are embedded using a length-prefixed
|
|||
|
|
wrapper over canonical `ReferenceBytes` from `ENC/ASL1-CORE v1`:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
EncodedRef =
|
|||
|
|
ref_len (u32)
|
|||
|
|
ref_bytes (byte[0..ref_len-1]) // canonical ReferenceBytes
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Where:
|
|||
|
|
|
|||
|
|
* `ref_bytes` MUST be the canonical `ReferenceBytes` encoding for a `Reference`:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
ReferenceBytes ::
|
|||
|
|
hash_id (u16)
|
|||
|
|
digest (byte[...]) // remaining bytes in the frame
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
* `ref_len` MUST be the exact length (in bytes) of `ref_bytes`, and MUST be ≥ 2.
|
|||
|
|
|
|||
|
|
Decoders MUST:
|
|||
|
|
|
|||
|
|
* Read `ref_len (u32)`, then `ref_bytes[0..ref_len-1]`.
|
|||
|
|
* Decode `ref_bytes` as `ReferenceBytes` per `ENC/ASL1-CORE v1`.
|
|||
|
|
* Reject encodings where:
|
|||
|
|
|
|||
|
|
* `ref_len < 2`, or
|
|||
|
|
* `ref_bytes` is not a valid `ReferenceBytes` sequence.
|
|||
|
|
|
|||
|
|
This pattern is identical to the `EncodedRef` used by `ENC/PEL-TRACE-DAG/1`.
|
|||
|
|
|
|||
|
|
#### 2.5.1 Optional `EncodedRef`
|
|||
|
|
|
|||
|
|
Optional `Reference` fields are encoded as:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
OptionalEncodedRef =
|
|||
|
|
has_ref (u8)
|
|||
|
|
[ EncodedRef ] // only if has_ref = 0x01
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
* `has_ref = 0x00` → no value present; no `EncodedRef` follows.
|
|||
|
|
* `has_ref = 0x01` → exactly one `EncodedRef` follows.
|
|||
|
|
* Any other `has_ref` value MUST be treated as an encoding error.
|
|||
|
|
|
|||
|
|
### 2.6 Embedded `StoreFailure` (`EncodedStoreFailure`)
|
|||
|
|
|
|||
|
|
`StoreFailure` (see §3.3) is embedded using:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
StoreFailureBytes ::
|
|||
|
|
phase (u8) // StoreFailurePhase
|
|||
|
|
error_code (u8) // StoreErrorCode
|
|||
|
|
failing_ref (EncodedRef)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Optional `StoreFailure` is encoded as:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
OptionalStoreFailureBytes ::
|
|||
|
|
has_store_failure (u8)
|
|||
|
|
[ store_failure (StoreFailureBytes) ] // if has_store_failure = 0x01
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
* `has_store_failure = 0x00` → no `store_failure` present.
|
|||
|
|
* `has_store_failure = 0x01` → exactly one `StoreFailureBytes` follows.
|
|||
|
|
* Any other value MUST be treated as an encoding error.
|
|||
|
|
|
|||
|
|
Decoders MUST:
|
|||
|
|
|
|||
|
|
* Validate `phase` and `error_code` are within the sets defined in `PEL/1-SURF`
|
|||
|
|
(or treat out-of-range values as encoding errors or semantic errors per policy).
|
|||
|
|
* Decode `failing_ref` via `EncodedRef`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Logical Surface Result Model (Reference)
|
|||
|
|
|
|||
|
|
This section restates, in condensed form, the logical PEL/1 surface result
|
|||
|
|
structure from `PEL/1-SURF`. The normative source for semantics is `PEL/1-SURF`;
|
|||
|
|
this profile only encodes the agreed structure.
|
|||
|
|
|
|||
|
|
### 3.1 SurfaceExecutionResult structure
|
|||
|
|
|
|||
|
|
`PEL/1-SURF` defines the logical payload of the surface ExecutionResult artifact
|
|||
|
|
as:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
SurfaceExecutionResult {
|
|||
|
|
pel1_version : uint16
|
|||
|
|
|
|||
|
|
core_result : ExecutionResultValue
|
|||
|
|
|
|||
|
|
scheme_ref : SchemeRef // echo
|
|||
|
|
program_ref : ProgramRef
|
|||
|
|
input_refs : InputRefList
|
|||
|
|
output_refs : OutputRefList
|
|||
|
|
|
|||
|
|
params_ref : optional ParamsRef
|
|||
|
|
|
|||
|
|
store_failure: optional StoreFailure
|
|||
|
|
trace_ref : optional TraceRef
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Where `ExecutionResultValue` is from `PEL/1-CORE` (§3.2), and:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
SchemeRef = Reference
|
|||
|
|
ProgramRef = Reference
|
|||
|
|
InputRef = Reference
|
|||
|
|
OutputRef = Reference
|
|||
|
|
ParamsRef = Reference
|
|||
|
|
TraceRef = Reference
|
|||
|
|
|
|||
|
|
InputRefList = list<InputRef>
|
|||
|
|
OutputRefList = list<OutputRef>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Semantics (summarised from `PEL/1-SURF`):
|
|||
|
|
|
|||
|
|
* `pel1_version` reaffirms the PEL major version (`1` for `PEL/1-CORE`).
|
|||
|
|
* `core_result` is the PEL/1-CORE execution result for this run.
|
|||
|
|
* `scheme_ref`, `program_ref`, `input_refs`, `params_ref` reflect the artifacts
|
|||
|
|
used to *start* the execution.
|
|||
|
|
* `output_refs` reflect the artifacts produced and successfully persisted by the
|
|||
|
|
surface for this run.
|
|||
|
|
* `store_failure`, when present, describes a **store-resolution error** that
|
|||
|
|
prevented `Exec_s` from being called, or prevented inputs/params from being
|
|||
|
|
resolved, in which case `core_result.status` is `INVALID_PROGRAM` or
|
|||
|
|
`INVALID_INPUTS` for store-level reasons.
|
|||
|
|
* `trace_ref`, when present, points at a trace Artifact whose logical value is
|
|||
|
|
defined by some trace profile (e.g. `PEL/TRACE-DAG/1`).
|
|||
|
|
|
|||
|
|
Store failures, transport errors, or environment failures that prevent
|
|||
|
|
construction of this artifact are **not** part of `SurfaceExecutionResult`;
|
|||
|
|
those are handled at the surface/API layer, not via this encoding.
|
|||
|
|
|
|||
|
|
### 3.2 ExecutionResultValue (from PEL/1-CORE)
|
|||
|
|
|
|||
|
|
From `PEL/1-CORE`:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
ExecutionStatus = uint8
|
|||
|
|
ExecutionErrorKind = uint8
|
|||
|
|
|
|||
|
|
ExecutionErrorSummary {
|
|||
|
|
kind : ExecutionErrorKind
|
|||
|
|
status_code : uint32
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
DiagnosticEntry {
|
|||
|
|
code : uint32
|
|||
|
|
message : OctetString // scheme-defined; SHOULD be UTF-8 text
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ExecutionResultValue {
|
|||
|
|
pel1_version : uint16
|
|||
|
|
status : ExecutionStatus
|
|||
|
|
scheme_ref : SchemeRef // Reference
|
|||
|
|
summary : ExecutionErrorSummary
|
|||
|
|
diagnostics : list<DiagnosticEntry>
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Invariants (from `PEL/1-CORE`):
|
|||
|
|
|
|||
|
|
* `pel1_version` MUST be 1.
|
|||
|
|
|
|||
|
|
* `status` and `summary` MUST satisfy:
|
|||
|
|
|
|||
|
|
* `status = OK` → `summary.kind = NONE`, `summary.status_code = 0`.
|
|||
|
|
* `status = SCHEME_UNSUPPORTED` → `summary.kind = SCHEME`.
|
|||
|
|
* `status = INVALID_PROGRAM` → `summary.kind = PROGRAM`.
|
|||
|
|
* `status = INVALID_INPUTS` → `summary.kind = INPUTS`.
|
|||
|
|
* `status = RUNTIME_FAILED` → `summary.kind = RUNTIME` and `summary.status_code != 0`.
|
|||
|
|
|
|||
|
|
* `scheme_ref` MUST match the scheme under which execution was interpreted.
|
|||
|
|
|
|||
|
|
* `diagnostics` MUST be deterministic for a given `(scheme_ref, program, inputs, params)`.
|
|||
|
|
|
|||
|
|
This profile defines a canonical inline encoding for `ExecutionResultValue` and
|
|||
|
|
`DiagnosticEntry` inside `ResultBytes`.
|
|||
|
|
|
|||
|
|
### 3.3 StoreFailure (from PEL/1-SURF)
|
|||
|
|
|
|||
|
|
`PEL/1-SURF` refines store-resolution errors via:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
StoreErrorCode = uint8
|
|||
|
|
|
|||
|
|
StoreErrorCode {
|
|||
|
|
NOT_FOUND = 1 // Store returned ERR_NOT_FOUND
|
|||
|
|
INTEGRITY = 2 // Store returned ERR_INTEGRITY
|
|||
|
|
UNSUPPORTED = 3 // Store returned ERR_UNSUPPORTED
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
StoreFailurePhase = uint8
|
|||
|
|
|
|||
|
|
StoreFailurePhase {
|
|||
|
|
PROGRAM = 1
|
|||
|
|
INPUT = 2
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
StoreFailure {
|
|||
|
|
phase : StoreFailurePhase
|
|||
|
|
error_code : StoreErrorCode
|
|||
|
|
failing_ref : Reference
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Semantics:
|
|||
|
|
|
|||
|
|
* `phase = PROGRAM` indicates the failure happened while resolving `program_ref`.
|
|||
|
|
* `phase = INPUT` indicates it happened while resolving an input or `params_ref`.
|
|||
|
|
* `failing_ref` MUST be the exact `Reference` passed to `get` that produced the error.
|
|||
|
|
* `error_code` MUST match the store’s reported error.
|
|||
|
|
|
|||
|
|
This encoding profile provides a canonical encoding for `StoreFailure` via
|
|||
|
|
`StoreFailureBytes` and `OptionalStoreFailureBytes` (§2.6, §4.3).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Encoding
|
|||
|
|
|
|||
|
|
This section defines:
|
|||
|
|
|
|||
|
|
* `DiagnosticEntryBytes` — inline diagnostic entry encoding;
|
|||
|
|
* `ExecutionResultValueBytes` — inline `ExecutionResultValue` encoding;
|
|||
|
|
* `StoreFailureBytes` / `OptionalStoreFailureBytes` — store-resolution diagnostics;
|
|||
|
|
* `ResultBytes` — top-level PEL/1 surface result encoding.
|
|||
|
|
|
|||
|
|
Field ordering, integer widths, and presence flags are fixed and MUST NOT vary.
|
|||
|
|
|
|||
|
|
### 4.1 DiagnosticEntry encoding
|
|||
|
|
|
|||
|
|
Logical:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
DiagnosticEntry {
|
|||
|
|
code : uint32
|
|||
|
|
message : OctetString
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Canonical encoding (matching `ENC/PEL-TRACE-DAG/1`):
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
DiagnosticEntryBytes ::
|
|||
|
|
code (u32)
|
|||
|
|
message (Blob32)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Where `Blob32` is defined in §2.4.
|
|||
|
|
|
|||
|
|
* `code (u32)` encodes the diagnostic or error code.
|
|||
|
|
* `message` is an opaque byte blob. Schemes MAY agree to use UTF-8 text here,
|
|||
|
|
but this encoding does not enforce it.
|
|||
|
|
|
|||
|
|
Decoders MUST:
|
|||
|
|
|
|||
|
|
* Read `code (u32)`.
|
|||
|
|
* Read `message` as `Blob32`.
|
|||
|
|
* Treat truncated blobs as encoding errors.
|
|||
|
|
|
|||
|
|
### 4.2 ExecutionResultValue encoding
|
|||
|
|
|
|||
|
|
Logical:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
ExecutionResultValue {
|
|||
|
|
pel1_version : uint16
|
|||
|
|
status : ExecutionStatus
|
|||
|
|
scheme_ref : SchemeRef
|
|||
|
|
summary : ExecutionErrorSummary
|
|||
|
|
diagnostics : list<DiagnosticEntry>
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Canonical encoding:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
ExecutionResultValueBytes ::
|
|||
|
|
pel1_version (u16)
|
|||
|
|
|
|||
|
|
status (u8) // ExecutionStatus
|
|||
|
|
scheme_ref (EncodedRef)
|
|||
|
|
|
|||
|
|
summary_kind (u8) // ExecutionErrorKind
|
|||
|
|
summary_status_code (u32) // ExecutionErrorSummary.status_code
|
|||
|
|
|
|||
|
|
diag_count (u32)
|
|||
|
|
diagnostics (DiagnosticEntryBytes[0..diag_count-1])
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Field semantics:
|
|||
|
|
|
|||
|
|
1. `pel1_version (u16)`
|
|||
|
|
|
|||
|
|
* MUST be `1` for `ExecutionResultValue` values defined by `PEL/1-CORE v0.3.x`.
|
|||
|
|
* Decoders:
|
|||
|
|
|
|||
|
|
* MUST accept `pel1_version = 1`.
|
|||
|
|
* MUST treat other values as encoding errors for this profile revision.
|
|||
|
|
|
|||
|
|
2. `status (u8)`
|
|||
|
|
|
|||
|
|
* Encodes `ExecutionStatus` as defined in `PEL/1-CORE`.
|
|||
|
|
* Decoders SHOULD treat out-of-range `status` values as encoding errors
|
|||
|
|
(rather than attempting to map them to an “unknown” variant).
|
|||
|
|
|
|||
|
|
3. `scheme_ref (EncodedRef)`
|
|||
|
|
|
|||
|
|
* Encodes the `SchemeRef` (`Reference`) under which the scheme was interpreted.
|
|||
|
|
* MUST match the `scheme_ref` at the surface level (§4.4.2, §6.2).
|
|||
|
|
|
|||
|
|
4. `summary_kind (u8)` and `summary_status_code (u32)`
|
|||
|
|
|
|||
|
|
* Encode `ExecutionErrorSummary.kind` and `ExecutionErrorSummary.status_code`
|
|||
|
|
respectively.
|
|||
|
|
* Encoders MUST set these to satisfy the invariants from `PEL/1-CORE §2.4`
|
|||
|
|
for the chosen `status`.
|
|||
|
|
* Decoders MAY validate consistency; inconsistency is a semantic error, not
|
|||
|
|
strictly an encoding error, but implementations MAY choose to reject such values.
|
|||
|
|
|
|||
|
|
5. `diag_count (u32)` and `diagnostics (DiagnosticEntryBytes[..])`
|
|||
|
|
|
|||
|
|
* Encodes the list of diagnostics as a `List<DiagnosticEntry>`.
|
|||
|
|
* `diag_count` is the number of entries; MAY be zero.
|
|||
|
|
* Decoders MUST reject truncated sequences where fewer than `diag_count`
|
|||
|
|
entries are present.
|
|||
|
|
|
|||
|
|
This layout is also suitable for use by other profiles that choose to store
|
|||
|
|
`ExecutionResultValue` as a dedicated Artifact; see §5 (informative note).
|
|||
|
|
|
|||
|
|
### 4.3 StoreFailure encoding
|
|||
|
|
|
|||
|
|
Logical:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
StoreFailure {
|
|||
|
|
phase : StoreFailurePhase
|
|||
|
|
error_code : StoreErrorCode
|
|||
|
|
failing_ref : Reference
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Canonical encoding:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
StoreFailureBytes ::
|
|||
|
|
phase (u8) // StoreFailurePhase
|
|||
|
|
error_code (u8) // StoreErrorCode
|
|||
|
|
failing_ref (EncodedRef)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Optional presence:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
OptionalStoreFailureBytes ::
|
|||
|
|
has_store_failure (u8)
|
|||
|
|
[ store_failure (StoreFailureBytes) ] // if has_store_failure = 0x01
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Field semantics:
|
|||
|
|
|
|||
|
|
1. `phase (u8)`
|
|||
|
|
|
|||
|
|
* Encodes `StoreFailurePhase`:
|
|||
|
|
|
|||
|
|
* `1` → PROGRAM
|
|||
|
|
* `2` → INPUT
|
|||
|
|
|
|||
|
|
* Decoders SHOULD treat other values as encoding errors or semantic errors
|
|||
|
|
per implementation policy.
|
|||
|
|
|
|||
|
|
2. `error_code (u8)`
|
|||
|
|
|
|||
|
|
* Encodes `StoreErrorCode`:
|
|||
|
|
|
|||
|
|
* `1` → NOT_FOUND
|
|||
|
|
* `2` → INTEGRITY
|
|||
|
|
* `3` → UNSUPPORTED
|
|||
|
|
|
|||
|
|
* Decoders SHOULD treat other values as encoding errors or semantic errors
|
|||
|
|
per implementation policy.
|
|||
|
|
|
|||
|
|
3. `failing_ref (EncodedRef)`
|
|||
|
|
|
|||
|
|
* Encodes the `Reference` that failed to resolve.
|
|||
|
|
|
|||
|
|
4. `has_store_failure (u8)`
|
|||
|
|
|
|||
|
|
* `0x00` → no `store_failure` present.
|
|||
|
|
* `0x01` → exactly one `StoreFailureBytes` follows.
|
|||
|
|
* Any other value MUST be treated as an encoding error.
|
|||
|
|
|
|||
|
|
Decoders MUST reject truncated values (e.g., missing `failing_ref` bytes).
|
|||
|
|
|
|||
|
|
### 4.4 Surface Result encoding (`ResultBytes`)
|
|||
|
|
|
|||
|
|
Logical (from §3.1):
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
SurfaceExecutionResult {
|
|||
|
|
pel1_version : uint16
|
|||
|
|
|
|||
|
|
core_result : ExecutionResultValue
|
|||
|
|
|
|||
|
|
scheme_ref : SchemeRef
|
|||
|
|
program_ref : ProgramRef
|
|||
|
|
input_refs : InputRefList
|
|||
|
|
output_refs : OutputRefList
|
|||
|
|
|
|||
|
|
params_ref : optional ParamsRef
|
|||
|
|
|
|||
|
|
store_failure: optional StoreFailure
|
|||
|
|
trace_ref : optional TraceRef
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Canonical encoding:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
ResultBytes ::
|
|||
|
|
pel1_version (u16)
|
|||
|
|
|
|||
|
|
scheme_ref (EncodedRef)
|
|||
|
|
program_ref (EncodedRef)
|
|||
|
|
|
|||
|
|
input_ref_count (u32)
|
|||
|
|
input_refs (EncodedRef[0..input_ref_count-1])
|
|||
|
|
|
|||
|
|
output_ref_count (u32)
|
|||
|
|
output_refs (EncodedRef[0..output_ref_count-1])
|
|||
|
|
|
|||
|
|
has_params_ref (u8)
|
|||
|
|
[ params_ref (EncodedRef) ] // if has_params_ref == 0x01
|
|||
|
|
|
|||
|
|
has_store_failure (u8)
|
|||
|
|
[ store_failure (StoreFailureBytes) ] // if has_store_failure == 0x01
|
|||
|
|
|
|||
|
|
has_trace_ref (u8)
|
|||
|
|
[ trace_ref (EncodedRef) ] // if has_trace_ref == 0x01
|
|||
|
|
|
|||
|
|
core_result (ExecutionResultValueBytes)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Field semantics:
|
|||
|
|
|
|||
|
|
1. `pel1_version (u16)`
|
|||
|
|
|
|||
|
|
* MUST be `1` for surface results representing `PEL/1-CORE v0.3.x` executions.
|
|||
|
|
* Decoders MUST treat any other value as an encoding error for this profile revision.
|
|||
|
|
|
|||
|
|
2. `scheme_ref (EncodedRef)`
|
|||
|
|
|
|||
|
|
* Encodes the scheme descriptor `SchemeRef` (`Reference`) for the run.
|
|||
|
|
* MUST match `ExecutionResultValue.scheme_ref` encoded inside
|
|||
|
|
`core_result.scheme_ref`; see §6.2.
|
|||
|
|
|
|||
|
|
3. `program_ref (EncodedRef)`
|
|||
|
|
|
|||
|
|
* Encodes the program Artifact reference used for this run.
|
|||
|
|
|
|||
|
|
4. `input_ref_count (u32)` and `input_refs (EncodedRef[..])`
|
|||
|
|
|
|||
|
|
* Encodes the ordered list of input references provided to the surface.
|
|||
|
|
* `input_ref_count` MAY be zero.
|
|||
|
|
* Encoders MUST preserve the logical order of `inputs`.
|
|||
|
|
* Decoders MUST reject truncated sequences with fewer than `input_ref_count`
|
|||
|
|
entries.
|
|||
|
|
|
|||
|
|
5. `output_ref_count (u32)` and `output_refs (EncodedRef[..])`
|
|||
|
|
|
|||
|
|
* Encodes the ordered list of output references produced and successfully
|
|||
|
|
persisted by the surface.
|
|||
|
|
* `output_ref_count` MAY be zero even when `core_result.status = OK` for
|
|||
|
|
schemes that legitimately produce no outputs.
|
|||
|
|
* Encoders MUST preserve the logical output order defined by the scheme/surface.
|
|||
|
|
* Decoders MUST reject truncated sequences.
|
|||
|
|
|
|||
|
|
6. `has_params_ref (u8)` and `params_ref (EncodedRef)`
|
|||
|
|
|
|||
|
|
* Encodes an optional parameters Artifact reference.
|
|||
|
|
* `has_params_ref = 0x00` → no `params_ref` present.
|
|||
|
|
* `has_params_ref = 0x01` → exactly one `EncodedRef` follows and encodes
|
|||
|
|
`params_ref`.
|
|||
|
|
* Any other `has_params_ref` value MUST be treated as an encoding error.
|
|||
|
|
* Surfaces that do not support parameter Artifacts MUST always emit
|
|||
|
|
`has_params_ref = 0x00`.
|
|||
|
|
|
|||
|
|
7. `has_store_failure (u8)` and `store_failure (StoreFailureBytes)`
|
|||
|
|
|
|||
|
|
* Encodes an optional `StoreFailure` as defined in §3.3 and §4.3.
|
|||
|
|
* `has_store_failure = 0x00` → no `store_failure` present.
|
|||
|
|
* `has_store_failure = 0x01` → exactly one `StoreFailureBytes` follows.
|
|||
|
|
* Any other `has_store_failure` value MUST be treated as an encoding error.
|
|||
|
|
* When `store_failure` is present:
|
|||
|
|
|
|||
|
|
* `core_result.status` MUST be `INVALID_PROGRAM` or `INVALID_INPUTS`
|
|||
|
|
according to the phase (PROGRAM or INPUT) as defined in `PEL/1-SURF`.
|
|||
|
|
* `core_result.summary.kind` MUST be `PROGRAM` or `INPUTS` accordingly.
|
|||
|
|
|
|||
|
|
8. `has_trace_ref (u8)` and `trace_ref (EncodedRef)`
|
|||
|
|
|
|||
|
|
* Encodes an optional reference to a trace Artifact (e.g. a `PEL/TRACE-DAG/1`
|
|||
|
|
value encoded under `ENC/PEL-TRACE-DAG/1`).
|
|||
|
|
* `has_trace_ref` uses the same conventions as `has_params_ref`.
|
|||
|
|
* Surfaces that never produce traces MUST always emit `has_trace_ref = 0x00`.
|
|||
|
|
|
|||
|
|
9. `core_result (ExecutionResultValueBytes)`
|
|||
|
|
|
|||
|
|
* Encodes the inline `ExecutionResultValue` for this run as defined in §4.2.
|
|||
|
|
* The `pel1_version`, `status`, `scheme_ref`, `summary`, and `diagnostics`
|
|||
|
|
fields MUST respect `PEL/1-CORE` invariants.
|
|||
|
|
* `core_result.scheme_ref` MUST equal the surface-level `scheme_ref`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. Result Artifact Binding
|
|||
|
|
|
|||
|
|
### 5.1 TypeTag
|
|||
|
|
|
|||
|
|
Result Artifacts for this profile MUST be ASL/1 Artifacts with:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Artifact {
|
|||
|
|
bytes = ResultBytes
|
|||
|
|
type_tag = TYPE_TAG_PEL1_RESULT_1
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Where:
|
|||
|
|
|
|||
|
|
* `TYPE_TAG_PEL1_RESULT_1` is a `TypeTag` with a concrete `tag_id` assigned in
|
|||
|
|
the global TypeTag registry for PEL/1 surface results.
|
|||
|
|
|
|||
|
|
This encoding profile:
|
|||
|
|
|
|||
|
|
* refers to `TYPE_TAG_PEL1_RESULT_1` symbolically; and
|
|||
|
|
* does not assign a numeric `tag_id` (that belongs in the registry).
|
|||
|
|
|
|||
|
|
### 5.2 Identity via ASL/1-CORE
|
|||
|
|
|
|||
|
|
With `ENC/ASL1-CORE v1` and the "ASL1" hash family (`HASH/ASL1`):
|
|||
|
|
|
|||
|
|
1. Canonical `ArtifactBytes` for a result Artifact:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
ArtifactBytes =
|
|||
|
|
encode_artifact_core_v1(
|
|||
|
|
Artifact{
|
|||
|
|
bytes = ResultBytes,
|
|||
|
|
type_tag = TYPE_TAG_PEL1_RESULT_1
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. Canonical `Reference` for any chosen `HashId = HID`:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
digest = H(ArtifactBytes) // H from HASH/ASL1 for HID
|
|||
|
|
reference = Reference { hash_id = HID,
|
|||
|
|
digest = digest }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
All conformant implementations using the same `(EncodingProfileId, HashId)` pair
|
|||
|
|
MUST agree on:
|
|||
|
|
|
|||
|
|
* `ResultBytes` for a given logical surface result value,
|
|||
|
|
* the resulting `ArtifactBytes` for the result Artifact,
|
|||
|
|
* the resulting `Reference`.
|
|||
|
|
|
|||
|
|
> **Informative note (ExecutionResultValue as Artifact)**
|
|||
|
|
> Other profiles MAY choose to store `ExecutionResultValue` as a dedicated
|
|||
|
|
> Artifact using `ExecutionResultValueBytes` as `Artifact.bytes` and a dedicated
|
|||
|
|
> TypeTag (e.g. `TYPE_TAG_PEL_EXECUTION_RESULT_VALUE_1`). Such a binding is
|
|||
|
|
> intentionally left out of this version; if introduced, it SHOULD reuse
|
|||
|
|
> `ExecutionResultValueBytes` exactly to preserve injectivity across inline and
|
|||
|
|
> stored forms.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. Canonicality & Determinism
|
|||
|
|
|
|||
|
|
### 6.1 Injectivity
|
|||
|
|
|
|||
|
|
The mapping:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
SurfaceExecutionResult -> ResultBytes
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
defined by this profile MUST be **injective**:
|
|||
|
|
|
|||
|
|
* If two logical `SurfaceExecutionResult` values differ (per `PEL/1-SURF` and
|
|||
|
|
`PEL/1-CORE` semantics), then:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
ResultBytes(V1) != ResultBytes(V2)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Injectivity is ensured by:
|
|||
|
|
|
|||
|
|
* fixed field ordering;
|
|||
|
|
* explicit presence flags for all optional references and store failures;
|
|||
|
|
* deterministic list ordering (`input_refs`, `output_refs`,
|
|||
|
|
`diagnostics`);
|
|||
|
|
* inclusion of all logically relevant fields.
|
|||
|
|
|
|||
|
|
Similarly, the mapping:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
ExecutionResultValue -> ExecutionResultValueBytes
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
MUST be injective.
|
|||
|
|
|
|||
|
|
### 6.2 Stability & consistency
|
|||
|
|
|
|||
|
|
For any fixed logical value and encoding profile version:
|
|||
|
|
|
|||
|
|
* All conformant encoders MUST produce the same `ExecutionResultValueBytes` and
|
|||
|
|
`ResultBytes`.
|
|||
|
|
* Encodings MUST be stable across implementations, platforms, and time.
|
|||
|
|
|
|||
|
|
Encoders MUST NOT:
|
|||
|
|
|
|||
|
|
* reorder list elements (`input_refs`, `output_refs`, `diagnostics`);
|
|||
|
|
* omit or reorder fields;
|
|||
|
|
* vary integer widths or encodings;
|
|||
|
|
* introduce alternative layouts for version negotiation.
|
|||
|
|
|
|||
|
|
In addition, encoders MUST enforce:
|
|||
|
|
|
|||
|
|
* `pel1_version` fields for both the surface result and the inline
|
|||
|
|
`ExecutionResultValue` are `1`.
|
|||
|
|
* `scheme_ref` in the surface header and `scheme_ref` inside
|
|||
|
|
`ExecutionResultValue` are identical.
|
|||
|
|
* When `store_failure` is present, `core_result.status` and
|
|||
|
|
`core_result.summary.kind` reflect `INVALID_PROGRAM`/`PROGRAM` or
|
|||
|
|
`INVALID_INPUTS`/`INPUTS` as mandated by `PEL/1-SURF`.
|
|||
|
|
|
|||
|
|
### 6.3 Extension and evolution (informative)
|
|||
|
|
|
|||
|
|
`ENC/PEL1-RESULT/1` is intended to evolve **additively**:
|
|||
|
|
|
|||
|
|
* New optional fields SHOULD be introduced via new encoding profiles or clearly
|
|||
|
|
versioned layouts, rather than overloading this layout in incompatible ways.
|
|||
|
|
* Any future revision that extends `ResultBytes` or `ExecutionResultValueBytes`
|
|||
|
|
MUST preserve all existing fields, their order, and their semantics for
|
|||
|
|
`pel1_version = 1`.
|
|||
|
|
* Changes that would alter the meaning of existing bytes (for the same logical
|
|||
|
|
value) MUST be expressed as a new profile or a new result TypeTag, not as a
|
|||
|
|
silent change to this profile.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. Error Handling (Encoding Layer)
|
|||
|
|
|
|||
|
|
Decoders for this profile MUST treat as **encoding errors**:
|
|||
|
|
|
|||
|
|
1. **Truncated values**
|
|||
|
|
|
|||
|
|
* Insufficient bytes to read any declared integer, length prefix, `EncodedRef`,
|
|||
|
|
`DiagnosticEntryBytes`, `StoreFailureBytes`, or `ExecutionResultValueBytes`.
|
|||
|
|
|
|||
|
|
2. **Invalid `pel1_version`**
|
|||
|
|
|
|||
|
|
* `pel1_version != 1` in either:
|
|||
|
|
|
|||
|
|
* the surface-level header (§4.4), or
|
|||
|
|
* `ExecutionResultValueBytes` (§4.2).
|
|||
|
|
|
|||
|
|
3. **Invalid presence flags**
|
|||
|
|
|
|||
|
|
* `has_params_ref`, `has_store_failure`, or `has_trace_ref` not in `{0x00, 0x01}`.
|
|||
|
|
|
|||
|
|
4. **Invalid `EncodedRef`**
|
|||
|
|
|
|||
|
|
* `ref_len < 2`, or
|
|||
|
|
* `ref_bytes` cannot be decoded as canonical `ReferenceBytes` under
|
|||
|
|
`ENC/ASL1-CORE v1`.
|
|||
|
|
|
|||
|
|
5. **Invalid list counts**
|
|||
|
|
|
|||
|
|
* Fewer entries than indicated by `input_ref_count`, `output_ref_count`, or
|
|||
|
|
`diag_count`.
|
|||
|
|
|
|||
|
|
6. **Invalid `Utf8String` (if used)**
|
|||
|
|
|
|||
|
|
* Any `Utf8String` field present in a future extension that is not valid UTF-8.
|
|||
|
|
|
|||
|
|
Decoders SHOULD also treat as encoding errors:
|
|||
|
|
|
|||
|
|
* `status` values outside the range defined by `PEL/1-CORE` for `ExecutionStatus`;
|
|||
|
|
* `summary_kind` values outside the range defined for `ExecutionErrorKind`;
|
|||
|
|
* `phase` or `error_code` values outside the ranges defined for `StoreFailurePhase`
|
|||
|
|
and `StoreErrorCode`, if the implementation chooses to enforce these at the
|
|||
|
|
encoding layer.
|
|||
|
|
|
|||
|
|
Decoders MAY treat as either encoding errors or semantic errors (per
|
|||
|
|
implementation policy):
|
|||
|
|
|
|||
|
|
* mismatches between `status` and `summary` invariants (e.g. `status = OK` but
|
|||
|
|
`summary.kind != NONE` or `summary.status_code != 0`);
|
|||
|
|
* inconsistencies between `store_failure` presence and `core_result.status` /
|
|||
|
|
`core_result.summary.kind`.
|
|||
|
|
|
|||
|
|
Mapping from encoding errors to external error codes (e.g.
|
|||
|
|
`ERR_PEL_RESULT_ENC_INVALID`) is implementation-specific. These are strictly
|
|||
|
|
encoding-layer issues; store failures, scheme errors, and runtime failures are
|
|||
|
|
represented inside `ExecutionResultValue` and `StoreFailure` and handled by
|
|||
|
|
PEL/1-CORE and PEL/1-SURF.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. Streaming & Implementation Notes
|
|||
|
|
|
|||
|
|
Encoders and decoders MUST support **single-pass** operation:
|
|||
|
|
|
|||
|
|
* **Encoding**:
|
|||
|
|
|
|||
|
|
* Encoders MUST be able to generate `ResultBytes` in a single forward pass over
|
|||
|
|
the logical `SurfaceExecutionResult`, assuming the structure is known in
|
|||
|
|
memory (or the list counts are precomputed).
|
|||
|
|
* They MAY need to compute `input_ref_count`, `output_ref_count`, and
|
|||
|
|
`diag_count` before emitting the corresponding lists.
|
|||
|
|
|
|||
|
|
* **Decoding**:
|
|||
|
|
|
|||
|
|
* Decoders MUST be able to decode `ResultBytes` in a single forward pass, with
|
|||
|
|
no backtracking.
|
|||
|
|
* All length prefixes appear before their content; no speculative reads are
|
|||
|
|
required.
|
|||
|
|
|
|||
|
|
For large results:
|
|||
|
|
|
|||
|
|
* Implementations MAY stream lists (e.g. `input_refs`, `output_refs`,
|
|||
|
|
`diagnostics`) to consumers as they decode them.
|
|||
|
|
* Implementations MUST ensure that any observable behavior (including error
|
|||
|
|
reporting and any reconstructed value) is independent of I/O chunking or
|
|||
|
|
buffer boundaries.
|
|||
|
|
|
|||
|
|
Implementations may also:
|
|||
|
|
|
|||
|
|
* compute hashes incrementally over `ArtifactBytes` (for result Artifacts),
|
|||
|
|
* pipeline decoding of `ResultBytes` directly into downstream consumers (e.g.
|
|||
|
|
inspection, provenance edge generators) without materializing the entire
|
|||
|
|
object in memory, as long as the logical value is representable.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. Conformance
|
|||
|
|
|
|||
|
|
An implementation is **ENC/PEL1-RESULT/1–conformant** if it:
|
|||
|
|
|
|||
|
|
1. **Implements the layouts exactly**
|
|||
|
|
|
|||
|
|
* Encodes and decodes `ExecutionResultValueBytes`, `StoreFailureBytes`, and
|
|||
|
|
`ResultBytes` exactly as defined in §4.2, §4.3, and §4.4.
|
|||
|
|
* Uses the correct field ordering, integer widths, list framing, and presence
|
|||
|
|
flags.
|
|||
|
|
|
|||
|
|
2. **Uses canonical sub-encodings**
|
|||
|
|
|
|||
|
|
* Embeds `Reference` values using `EncodedRef` over canonical `ReferenceBytes`
|
|||
|
|
(`ENC/ASL1-CORE v1`).
|
|||
|
|
* Encodes `DiagnosticEntry` using `DiagnosticEntryBytes` with `Blob32` as in
|
|||
|
|
§4.1.
|
|||
|
|
* Encodes `StoreFailure` using `StoreFailureBytes` as in §4.3.
|
|||
|
|
|
|||
|
|
3. **Preserves injectivity and stability**
|
|||
|
|
|
|||
|
|
* Ensures distinct logical `SurfaceExecutionResult` values produce distinct
|
|||
|
|
`ResultBytes`.
|
|||
|
|
* Ensures distinct logical `ExecutionResultValue` values produce distinct
|
|||
|
|
`ExecutionResultValueBytes`.
|
|||
|
|
* Ensures the same logical values always encode to the same bytes (no
|
|||
|
|
configuration or environment affecting layout).
|
|||
|
|
|
|||
|
|
4. **Binds to result Artifacts correctly**
|
|||
|
|
|
|||
|
|
* When forming surface result Artifacts, sets:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Artifact.bytes = ResultBytes
|
|||
|
|
Artifact.type_tag = TYPE_TAG_PEL1_RESULT_1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
* Uses `ENC/ASL1-CORE v1` and `HASH/ASL1` for identity derivation.
|
|||
|
|
|
|||
|
|
5. **Respects layering**
|
|||
|
|
|
|||
|
|
* Does not depend on TGK, CIL, FER, FCT, or OI to encode or decode result
|
|||
|
|
values.
|
|||
|
|
* Does not reinterpret or override `ExecutionResultValue` or `StoreFailure`
|
|||
|
|
semantics beyond what is specified in `PEL/1-CORE` and `PEL/1-SURF`.
|
|||
|
|
|
|||
|
|
Everything else — storage configuration, trace persistence, provenance edges,
|
|||
|
|
receipts, facts, overlays — is outside the scope of this encoding profile,
|
|||
|
|
provided it does not contradict the rules above.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. Informative Example
|
|||
|
|
|
|||
|
|
> This example illustrates field layout only.
|
|||
|
|
> Values and hex are illustrative, not normative test vectors.
|
|||
|
|
|
|||
|
|
Consider a simple run with:
|
|||
|
|
|
|||
|
|
* `pel1_version = 1`
|
|||
|
|
* `scheme_ref = S`
|
|||
|
|
* `program_ref = P`
|
|||
|
|
* Inputs: `input_refs = [I0, I1]`
|
|||
|
|
* Outputs: `output_refs = [O0]`
|
|||
|
|
* `params_ref = absent`
|
|||
|
|
* `store_failure = absent`
|
|||
|
|
* `trace_ref = T`
|
|||
|
|
* Inline `core_result : ExecutionResultValue`:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
pel1_version = 1
|
|||
|
|
status = OK
|
|||
|
|
scheme_ref = S
|
|||
|
|
summary.kind = NONE
|
|||
|
|
summary.status_code = 0
|
|||
|
|
diagnostics = [] // empty
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Then `ResultBytes` are:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
pel1_version = 0001 ; u16
|
|||
|
|
|
|||
|
|
scheme_ref = EncodedRef(S)
|
|||
|
|
program_ref = EncodedRef(P)
|
|||
|
|
|
|||
|
|
input_ref_count = 00000002 ; 2
|
|||
|
|
input_refs = EncodedRef(I0)
|
|||
|
|
EncodedRef(I1)
|
|||
|
|
|
|||
|
|
output_ref_count = 00000001 ; 1
|
|||
|
|
output_refs = EncodedRef(O0)
|
|||
|
|
|
|||
|
|
has_params_ref = 00 ; none
|
|||
|
|
|
|||
|
|
has_store_failure = 00 ; none
|
|||
|
|
|
|||
|
|
has_trace_ref = 01
|
|||
|
|
trace_ref = EncodedRef(T)
|
|||
|
|
|
|||
|
|
; Inline core_result (ExecutionResultValueBytes)
|
|||
|
|
pel1_version = 0001
|
|||
|
|
status = 00 ; OK (ExecutionStatus)
|
|||
|
|
scheme_ref = EncodedRef(S)
|
|||
|
|
summary_kind = 00 ; NONE (ExecutionErrorKind)
|
|||
|
|
summary_status_code = 00000000 ; 0
|
|||
|
|
|
|||
|
|
diag_count = 00000000 ; no diagnostics
|
|||
|
|
; (no DiagnosticEntryBytes follow)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Where each `EncodedRef(X)` is:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
ref_len(X) (u32) || ReferenceBytes(X)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
with `ReferenceBytes(X)` = `hash_id (u16)` + `digest` bytes, per
|
|||
|
|
`ENC/ASL1-CORE v1`.
|
|||
|
|
|
|||
|
|
All conformant encoders MUST produce the same `ResultBytes` for this logical
|
|||
|
|
surface result value; all conformant decoders MUST reconstruct the same logical
|
|||
|
|
value from those bytes.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Document History
|
|||
|
|
|
|||
|
|
* **0.3.0 (2025-11-17):** Promoted the ExecutionResult encoding profile to Approved status and pinned PH06 vectors/tests to this canonical layout.
|
|||
|
|
* **0.2.3 (2025-11-17):** Aligned logical shape and encoding with `PEL/1-SURF v0.2.1` (added `StoreFailure` encoding, removed `exec_result_ref`, renamed inline `result_value` to `core_result`).
|
|||
|
|
* **0.2.2 (2025-11-16):** Tightened consistency rules between surface header and inline `ExecutionResultValue`, clarified PEL vs encoding versioning, and strengthened decoding recommendations for out-of-range status values.
|
|||
|
|
* **0.2.1 (2025-11-16):** Aligned `ExecutionResultValueBytes` field order with `PEL/1-CORE`, clarified flag semantics for unsupported optional fields, and added an evolution note for future extensions.
|
|||
|
|
* **0.2.0 (2025-11-16):** Integrated earlier CODEx draft ideas; defined explicit `ExecutionResultValueBytes`, aligned diagnostics encoding with `ENC/PEL-TRACE-DAG/1`, and fixed full `ResultBytes` layout with `EncodedRef`/`u32` list framing.
|
|||
|
|
* **0.1.0 (2025-11-16):** Initial skeleton for `ENC/PEL1-RESULT/1` (high-level scope, dependencies, and rough layout outline).
|