amduat/tier1/enc-pel1-result-1.md
2025-12-20 12:35:10 +01:00

34 KiB
Raw Permalink Blame History

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]

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.xExecutionResultValue, 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.xDiagnosticEntry 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:

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:

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:

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:

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:

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:

    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:

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:

StoreFailureBytes ::
  phase       (u8)        // StoreFailurePhase
  error_code  (u8)        // StoreErrorCode
  failing_ref (EncodedRef)

Optional StoreFailure is encoded as:

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:

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:

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:

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 = OKsummary.kind = NONE, summary.status_code = 0.
    • status = SCHEME_UNSUPPORTEDsummary.kind = SCHEME.
    • status = INVALID_PROGRAMsummary.kind = PROGRAM.
    • status = INVALID_INPUTSsummary.kind = INPUTS.
    • status = RUNTIME_FAILEDsummary.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:

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 stores 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:

DiagnosticEntry {
  code    : uint32
  message : OctetString
}

Canonical encoding (matching ENC/PEL-TRACE-DAG/1):

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:

ExecutionResultValue {
  pel1_version : uint16
  status       : ExecutionStatus
  scheme_ref   : SchemeRef
  summary      : ExecutionErrorSummary
  diagnostics  : list<DiagnosticEntry>
}

Canonical encoding:

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:

StoreFailure {
  phase       : StoreFailurePhase
  error_code  : StoreErrorCode
  failing_ref : Reference
}

Canonical encoding:

StoreFailureBytes ::
  phase       (u8)       // StoreFailurePhase
  error_code  (u8)       // StoreErrorCode
  failing_ref (EncodedRef)

Optional presence:

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):

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:

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:

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:

    ArtifactBytes =
      encode_artifact_core_v1(
        Artifact{
          bytes    = ResultBytes,
          type_tag = TYPE_TAG_PEL1_RESULT_1
        }
      )
    
  2. Canonical Reference for any chosen HashId = HID:

    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:

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:

    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:

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/1conformant 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:

      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:

    pel1_version        = 1
    status              = OK
    scheme_ref          = S
    summary.kind        = NONE
    summary.status_code = 0
    diagnostics         = []   // empty
    

Then ResultBytes are:

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:

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).