* **Deterministic & stable** — same `EdgeBody` → same `EdgeBytes` across implementations and time.
* **Streaming-friendly** — encoders, decoders, and hashers can operate in a single forward-only pass.
In line with `TGK/1-CORE`:
* Each EdgeArtifact encodes **exactly one** logical edge (one `EdgeBody`).
* All TGK edges are represented as ordinary ASL/1 Artifacts plus their ASL `Reference` identities; this profile introduces no additional identity or node/edge ID layer.
> **Non-goal:** This profile does **not** define what any particular `EdgeTypeId` “means”, nor how graphs are stored, indexed, or traversed. Those behaviors are defined by `TGK/1-CORE`, TGK type catalogs, and higher-layer profiles.
---
## 1. Scope & Layering
### 1.1 Purpose
This specification defines:
* The **binary layout** of:
*`EdgeBytes` — canonical encoding for `EdgeBody`.
*`EncodedRef` — an internal wrapper for embedding ASL `Reference`s.
* Canonical field ordering and integer widths.
* How `EdgeBytes` are bound into EdgeArtifacts and converted into `EdgeRef` identity.
It does **not** define:
* TGK graph semantics or provenance algorithms (`TGK/1-CORE`, `TGK/PROV/1`).
* Store or transport APIs (`ASL/1-STORE`, deployment profiles).
* Edge-type catalogs (`TGK/TYPES-*`) or policy.
### 1.2 Layering constraints
In line with `SUBSTRATE/STACK-OVERVIEW` and `TGK/1-CORE`:
*`ENC/TGK1-EDGE/1` is a **TGK edge-encoding profile**, not a kernel primitive.
* It MUST NOT:
* redefine `Artifact`, `Reference`, `HashId`, or `TypeTag` (from `ASL/1-CORE`);
* redefine `Node`, `EdgeBody`, or `EdgeTypeId` (from `TGK/1-CORE`);
* embed store, provenance, or policy semantics into its layout.
* It defines exactly one canonical encoding for `EdgeBody` values under the profile ID `TGK1_EDGE_ENC_V1`.
TGK/1-CORE sees this profile as providing a partial function:
```text
decode_edge_payload_TGK1_EDGE :
OctetString -> EdgeBody | error
```
that is:
* **partial** — may fail with an error for some inputs;
* **deterministic** — a pure function of its input bytes, with no dependence on environment or mutable state;
* **side-effect free** — decoding does not consult stores, catalogs, or policy.
Artifacts whose `type_tag` selects this profile use `decode_edge_payload_TGK1_EDGE` as their TGK edge decoder in the sense of `TGK/1-CORE §3.2`.
---
## 2. Conventions
### 2.1 RFC 2119 terms
The key words **MUST**, **MUST NOT**, **SHOULD**, **MAY**, etc. are to be interpreted as described in RFC 2119.
### 2.2 Integer encodings
All multi-byte integers are encoded as **big-endian** (network byte order), as in `ENC/ASL1-CORE`:
*`u8` — 1 byte
*`u16` — 2 bytes
*`u32` — 4 bytes
*`u64` — 8 bytes
Only fixed-width integers are used.
### 2.3 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 of `T`.
### 2.4 Embedded Reference (`EncodedRef`)
Within `EdgeBytes`, ASL/1 `Reference` values are embedded using a length-prefixed wrapper over canonical `ReferenceBytes` from `ENC/ASL1-CORE`:
*`ref_bytes` MUST be the canonical `ReferenceBytes` encoding of some `Reference` value under `ENC/ASL1-CORE v1.x`:
```text
ReferenceBytes ::
hash_id (u16)
digest (byte[...]) // remaining bytes in the frame
```
*`ref_len` MUST be the exact byte length of `ref_bytes` and MUST be ≥ 2.
Decoders MUST:
1. Read `ref_len (u32)`.
2. Read exactly `ref_len` bytes as `ref_bytes`.
3. Decode `ref_bytes` as `ReferenceBytes` per `ENC/ASL1-CORE v1.x`.
4. Reject encodings where:
*`ref_len < 2`, or
*`ref_bytes` is not a valid `ReferenceBytes` sequence (e.g. truncated or improperly framed in its context).
If the implementation also implements `HASH/ASL1` and recognizes the decoded `hash_id`, it MUST apply any length checks required by `ENC/ASL1-CORE` / `HASH/ASL1` for that `HashId` (e.g. fixed digest length). Failures MUST be treated as encoding/integrity errors.
`EncodedRef` is purely an internal framing wrapper for this profile; it introduces no additional semantics beyond “a `Reference` encoded canonically and length-prefixed so it can be embedded in larger structures”.
This pattern mirrors `EncodedRef` from `ENC/PEL-TRACE-DAG/1` for cross-profile consistency.
### 2.5 Encoding version field (`edge_version`)
`EdgeBytes` includes an `edge_version (u16)` field:
* For `TGK1_EDGE_ENC_V1`, encoders **MUST** always write `edge_version = 1`.
* Decoders for this profile:
* **MUST** accept `edge_version = 1`; and
* **MUST** treat any other value as “**not this encoding**” and fail decoding.
Within this profile, `edge_version` is a **guard word**, not an evolution mechanism:
* This document will never assign any other meaning than “constant value 1” to `edge_version` for `TGK1_EDGE_ENC_V1`.
* Values other than `1` simply indicate that the bytes are not an `EdgeBytes` value for this profile.
Any incompatible change to the `EdgeBytes` layout MUST be expressed as a **new encoding profile** (e.g. `TGK1_EDGE_ENC_V2` with its own Profile ID, and almost certainly a new `TypeTag`), not by reusing this profile with `edge_version = 2`.
Append-only extensions that would change the canonical mapping from `EdgeBody` to bytes are also out of scope for this profile; they belong in new profiles. Canonical `EdgeBody → EdgeBytes` mapping for `TGK1_EDGE_ENC_V1` is fixed and permanently tied to `edge_version = 1`.
---
## 3. Logical Model Reference (from TGK/1-CORE)
> **Source of truth:** `TGK/1-CORE`.
> This section is an informative restatement; in any conflict, `TGK/1-CORE` governs.
### 3.1 Node
```text
Node := Reference // ASL/1 Reference
```
Nodes are graph vertices identified solely by their `Reference` value.
### 3.2 EdgeTypeId
```text
EdgeTypeId = uint32
```
Semantics of particular `EdgeTypeId` values are defined by TGK type catalogs and profiles, not by this document.
### 3.3 EdgeBody
```text
EdgeBody {
type: EdgeTypeId
from: Node[] // ordered, MAY be empty
to: Node[] // ordered, MAY be empty
payload: Reference // always present
}
```
Relevant invariant from `TGK/1-CORE`:
> **TGK/EDGE-NONEMPTY-ENDPOINT/CORE/1**
> For a well-formed `EdgeBody`, at least one of `from` or `to` **MUST** be non-empty.
> An `EdgeBody` with both `from = []` and `to = []` is invalid and MUST NOT be produced or accepted as a TGK edge.
Other notes from `TGK/1-CORE`:
* Duplicates within `from` or `to` are allowed.
*`payload` may also appear in `from` or `to`.
* Semantics of such patterns, if any, are profile-specific.
`ENC/TGK1-EDGE/1` encodes exactly these fields and MUST NOT introduce additional logical data at the `EdgeBody` level.
---
## 4. EdgeBody Encoding
### 4.1 Overall layout: `EdgeBytes`
The canonical encoding of an `EdgeBody` under `TGK1_EDGE_ENC_V1` is a single self-contained byte sequence:
```text
EdgeBytes ::
edge_version (u16)
type_id (u32) // EdgeTypeId
from_count (u32)
from_nodes (EncodedRef[0..from_count-1])
to_count (u32)
to_nodes (EncodedRef[0..to_count-1])
payload_ref (EncodedRef)
```
`EdgeBytes` is treated as an indivisible frame. When embedded in larger structures or protocols, the enclosing layer is responsible for providing the frame boundaries (e.g. via a length-prefix or message framing).
Field roles:
1.**edge_version (u16)**
* Guard word for this encoding profile.
* For `TGK1_EDGE_ENC_V1`, encoders **MUST** set `edge_version = 1` for all values.
* Decoders for this profile:
* **MUST** accept `edge_version = 1`; and
* **MUST** treat any other value as “not a `TGK1_EDGE_ENC_V1` edge payload” and fail decoding.
`edge_version` is not a version knob for evolving `TGK1_EDGE_ENC_V1`; it is a constant sanity check to quickly reject mismatched bytes.
2.**type_id (u32)**
* Encodes `EdgeBody.type : EdgeTypeId`.
* The meaning of each `EdgeTypeId` value is external to this spec.
3.**from_count (u32)** and **from_nodes**
*`from_count` is the length of `EdgeBody.from`.
*`from_nodes` is a list of `from_count``EncodedRef` entries, each encoding a `Node` (i.e. a `Reference`).
* Order MUST match the logical `from` list; duplicates are allowed; MAY be zero-length.
4.**to_count (u32)** and **to_nodes**
*`to_count` is the length of `EdgeBody.to`.
*`to_nodes` is a list of `to_count``EncodedRef` entries.
* Order MUST match the logical `to` list; duplicates are allowed; MAY be zero-length.
5.**payload_ref (EncodedRef)**
* Encodes `EdgeBody.payload : Reference`.
* Always present and encoded as a single `EncodedRef`.
### 4.2 Encoding procedure (normative)
Let `E` be a logical `EdgeBody` value. The canonical encoding function:
```text
encode_edgebody_tgk1_v1 : EdgeBody -> EdgeBytes
```
is defined as:
1. Set `edge_version = 1`.
2. Emit `edge_version` as `u16`.
3. Emit `E.type` as `type_id (u32)`.
4. Let `from_count = len(E.from)`; emit `from_count (u32)`.
5. For each `Node` in `E.from` in order:
* Let `R` be that `Node` (an ASL `Reference` value).
* Encode `R` as canonical `ReferenceBytes` using `ENC/ASL1-CORE v1.x`.
* Wrap as `EncodedRef` (see §2.4) and append.
6. Let `to_count = len(E.to)`; emit `to_count (u32)`.
7. For each `Node` in `E.to` in order:
* Encode as `EncodedRef` as above and append.
8. Encode `E.payload` as canonical `ReferenceBytes`, wrap as `EncodedRef`, and append as `payload_ref`.
9. Enforce the TGK non-empty endpoint invariant at encoding time:
* If `from_count == 0`**and**`to_count == 0`, the encoder MUST fail and MUST NOT produce `EdgeBytes` for this `EdgeBody` under this profile.
> **TGK1-EDGE-NONEMPTY/ENC/1**
> Encoders for `TGK1_EDGE_ENC_V1` **MUST** reject any attempt to encode an `EdgeBody` with `from = []` and `to = []`.
> Such a value is not a well-formed TGK edge per `TGK/1-CORE` and MUST NOT be emitted as an EdgeArtifact payload.
### 4.3 Decoding procedure (normative)
Given a byte slice known to contain exactly one `EdgeBytes` frame under this profile, the canonical decoding function:
* If `edge_version != 1`, fail with an encoding error (e.g. “not `TGK1_EDGE_ENC_V1`”).
2. Read `type_id (u32)`.
3. Read `from_count (u32)`.
* For `i = 0 .. from_count-1`, read and decode one `EncodedRef` as a `Reference` and append to `from_nodes`.
4. Read `to_count (u32)`.
* For `j = 0 .. to_count-1`, read and decode one `EncodedRef` and append to `to_nodes`.
5. Read `payload_ref` as a single `EncodedRef` and decode to `payload : Reference`.
6. If `from_count == 0`**and**`to_count == 0`, fail with an encoding error:
* This violates `TGK/EDGE-NONEMPTY-ENDPOINT/CORE/1` and `TGK1-EDGE-NONEMPTY/ENC/1`.
7. If the decoding context expects an isolated `EdgeBytes` value:
* After step 5 (or 6), if any unread bytes remain in the slice, the decoder MUST treat this as an encoding error (trailing data).
8. Construct and return:
```text
EdgeBody {
type = EdgeTypeId(type_id)
from = from_nodes
to = to_nodes
payload = payload
}
```
Decoders MUST additionally treat as encoding errors:
* truncated sequences (insufficient bytes for any declared field or `EncodedRef`);
* invalid `EncodedRef` encodings (see §2.4);
* any integer reads that cannot be completed because the input ends early.
`decode_edgebody_tgk1_v1` MUST be deterministic and MUST NOT depend on any external configuration beyond:
* the bytes in the `EdgeBytes` frame; and
* the static definition of `ENC/ASL1-CORE v1.x` used to decode embedded `ReferenceBytes`.
Recognition of `type_id` values (as supported or not in a given ExecutionEnvironment) is handled by `TGK/1-CORE` and the local catalog. This profile always decodes the raw `EdgeBody` structure, regardless of whether the environment later chooses to treat it as an EdgeArtifact.
---
## 5. EdgeArtifact Binding & Profile Selection
### 5.1 EdgeArtifact shape
Under this profile, EdgeArtifacts MUST be ASL/1 Artifacts of the form:
ExecutionEnvironments that wish to treat such Artifacts as TGK edges MUST:
* include `TYPE_TAG_TGK1_EDGE_V1.tag_id` in their configured `EDGE_TAG_SET`; and
* register `TGK1_EDGE_ENC_V1` as the edge-encoding profile for that tag, so that `decode_edge_payload_TGK1_EDGE` is used for those Artifacts’`bytes`.
### 5.2 Integration with TGK/1-CORE’s `decode_edge_payload_P`
For ExecutionEnvironments that activate `TGK1_EDGE_ENC_V1` for `TYPE_TAG_TGK1_EDGE_V1`, the corresponding `decode_edge_payload_P` function from `TGK/1-CORE §3.2` is:
* apply `decode_edge_payload_TGK1_EDGE` only to Artifacts whose `type_tag.tag_id` is configured to use this profile; and
* treat any decoding failure as “not a valid edge payload for this profile”.
Multi-profile behavior (e.g., co-existence with other edge encodings) is governed by `TGK/1-CORE §3.2`. In particular:
* If more than one active profile successfully decodes the same `Artifact.bytes`, all such profiles MUST decode to the same logical `EdgeBody` value.
* If two active profiles decode the same bytes to different `EdgeBody` values, the ExecutionEnvironment MUST NOT treat that Artifact as an EdgeArtifact until the conflict is resolved.
---
## 6. EdgeRef Identity via ASL/1-CORE
Given:
*`EdgeBytes` from §4;
* an `EdgeArtifact`:
```text
A_edge = Artifact {
bytes = EdgeBytes
type_tag = TYPE_TAG_TGK1_EDGE_V1
}
```
*`ENC/ASL1-CORE v1.x` for canonical `ArtifactBytes`;
* a hash algorithm `H` with `HashId = HID` from `HASH/ASL1`,
the canonical `EdgeRef : Reference` (the edge identity) is:
* encoding all logical fields (`type`, `from`, `to`, `payload`);
* preserving list order exactly;
* using a fixed, explicit binary layout.
### 7.2 Stability
For the fixed profile `TGK1_EDGE_ENC_V1` (with the guard word `edge_version = 1`):
* The same logical `EdgeBody` MUST always encode to the same `EdgeBytes` across:
* implementations,
* platforms,
* executions,
* and time.
Encoders MUST NOT:
* reorder elements of `from` or `to`;
* alter integer widths or endianness;
* introduce alternative layouts for any field;
* use any `edge_version` other than `1`.
---
## 8. Error Handling (Encoding Layer)
Decoders for this profile MUST treat as **encoding errors** (to be surfaced as some error category at the API boundary):
1.**Guard word mismatch**
*`edge_version != 1`.
2.**Truncated fields**
* Not enough bytes to read any declared field (`u16`, `u32`, `EncodedRef`, list elements).
3.**Invalid `EncodedRef`**
*`ref_len < 2`; or
*`ref_bytes` is not a valid `ReferenceBytes` sequence per `ENC/ASL1-CORE v1.x`; or
* (when `HASH/ASL1` is implemented and `hash_id` is known) the digest length implied by `ref_bytes` does not match the canonical length for that `HashId`.
4.**Empty endpoints**
*`from_count == 0`**and**`to_count == 0` (violation of `TGK/EDGE-NONEMPTY-ENDPOINT/CORE/1`).
5.**Inconsistent list lengths**
* Fewer actual `EncodedRef` entries than indicated by `from_count` or `to_count`.
6.**Trailing data in isolated contexts**
* Additional bytes remaining after a full `EdgeBytes` value has been decoded, when the decoding context expects exactly one `EdgeBytes` frame.
Translating these into concrete error codes (e.g. `ERR_TGK1_EDGE_ENC_INVALID`) is implementation-specific, but MUST result in rejection of the payload as an `EdgeBytes` value under this profile.
Semantic errors about `EdgeTypeId` recognition or edge-type-specific constraints are handled by TGK catalogs and higher profiles, not at the encoding layer.
---
## 9. Streaming & Implementation Notes
Implementations MUST be able to encode and decode `EdgeBytes` in a **single forward-only pass**:
* All length prefixes (`from_count`, `to_count`, `ref_len`) precede their content.
* Decoders MUST NOT require backtracking to interpret the structure.
For large edges (many endpoints):
* Encoders MAY stream `EncodedRef` entries as they are generated.
* Decoders MAY stream `EncodedRef` entries to consumers or hashers as they are read.
Any such streaming strategy MUST be observationally equivalent to decoding the entire `EdgeBytes` into an `EdgeBody` in memory and MUST respect the canonical layout.
---
## 10. Conformance
An implementation is **ENC/TGK1-EDGE/1–conformant** if, for `TGK1_EDGE_ENC_V1`, it:
* Implements `encode_edgebody_tgk1_v1` and `decode_edgebody_tgk1_v1` exactly as specified in §4.
* Always writes `edge_version = 1` when encoding.
* Accepts only `edge_version = 1` and treats any other value as “not this encoding”.
2.**Uses `EncodedRef` correctly**
* Embeds `Reference` values via `EncodedRef` as in §2.4.
* Uses canonical `ReferenceBytes` from `ENC/ASL1-CORE v1.x` when forming `ref_bytes`.
* Applies `HASH/ASL1` length checks for known `HashId`s when available.
3.**Enforces TGK invariants at the encoding layer**
* Rejects encodings with both `from` and `to` empty (`TGK1-EDGE-NONEMPTY/ENC/1`).
* Treats malformed payloads as encoding errors as per §8.
4.**Binds EdgeBytes into EdgeArtifacts correctly**
* When forming EdgeArtifacts, sets:
```text
Artifact.bytes = EdgeBytes
Artifact.type_tag = TYPE_TAG_TGK1_EDGE_V1
```
* Does not embed additional logical data into the Artifact beyond `EdgeBody` and `type_tag`.
5.**Derives EdgeRef identity via ASL/1-CORE**
* Uses `ENC/ASL1-CORE v1` and `HASH/ASL1` for identity, as in §6.
* Does not introduce alternative edge identity mechanisms at this layer.
6.**Integrates with TGK/1-CORE profile selection**
* Applies `decode_edge_payload_TGK1_EDGE` only to Artifacts whose `type_tag.tag_id` is configured for this profile.
* Respects multi-profile behavior rules from `TGK/1-CORE §3.2` when other edge encodings are also active.
7.**Preserves injectivity and stability**
* Distinct `EdgeBody` values always produce distinct `EdgeBytes`.
* The same `EdgeBody` always produces the same `EdgeBytes` under this profile.
Everything else — storage layout, access protocols, graph indexes, provenance algorithms, and edge-type semantics — is defined by `ASL/1-STORE`, `TGK/1-CORE`, TGK catalogs, and higher-layer profiles.
---
## 11. Informative Example (Sketch)
> Non-normative; values and hex are illustrative only.
Consider an edge:
```text
EdgeBody {
type = 0x00000010 // EDGE_EXECUTION (for example)
from = [N_prog, N_input]
to = [N_output]
payload = R_receipt
}
```
Where `N_prog`, `N_input`, `N_output`, and `R_receipt` are `Reference` values with canonical `ReferenceBytes`:
These `EdgeBytes` become `Artifact.bytes` for an EdgeArtifact with `type_tag = TYPE_TAG_TGK1_EDGE_V1`. All conformant encoders MUST produce the same bytes for the same logical `EdgeBody`; all conformant decoders MUST reconstruct the same `EdgeBody` from those bytes.
---
**End of `ENC/TGK1-EDGE/1 v0.1.0 — Canonical Encoding for TGK EdgeArtifacts` (draft).**
---
## Document History
* **0.1.0 (2025-11-16):** Registered as Tier-1 spec and aligned to the Amduat 2.0 substrate baseline.