214 lines
4.8 KiB
Markdown
214 lines
4.8 KiB
Markdown
# ENC-ASL-LOG
|
|
|
|
### Encoding Specification for ASL Append-Only Log
|
|
|
|
---
|
|
|
|
## 1. Purpose
|
|
|
|
This document defines the **exact encoding** of the ASL append-only log.
|
|
|
|
It translates **ASL/LOG/1** semantics into a deterministic **bytes-on-disk** format.
|
|
|
|
It does **not** define log semantics (see `ASL/LOG/1`).
|
|
|
|
---
|
|
|
|
## 2. Encoding Principles
|
|
|
|
1. **Little-endian** integers
|
|
2. **Packed structures** (no compiler padding)
|
|
3. **Forward-compatible** versioning via header fields
|
|
4. **Deterministic serialization**: identical log content -> identical bytes
|
|
5. **Hash-chained integrity** as defined by ASL/LOG/1
|
|
|
|
---
|
|
|
|
## 3. Log File Layout
|
|
|
|
```
|
|
+----------------+
|
|
| LogHeader |
|
|
+----------------+
|
|
| LogRecord[] |
|
|
+----------------+
|
|
```
|
|
|
|
* **LogHeader**: fixed-size, mandatory, begins file
|
|
* **LogRecord[]**: append-only entries, variable number
|
|
|
|
---
|
|
|
|
## 4. LogHeader
|
|
|
|
```c
|
|
#pragma pack(push,1)
|
|
typedef struct {
|
|
uint64_t magic; // "ASLLOG01"
|
|
uint32_t version; // Encoding version (1)
|
|
uint32_t header_size; // Total header bytes including this struct
|
|
uint64_t flags; // Reserved, must be zero for v1
|
|
} LogHeader;
|
|
#pragma pack(pop)
|
|
```
|
|
|
|
Notes:
|
|
|
|
* `magic` is ASCII bytes: `0x41 0x53 0x4c 0x4c 0x4f 0x47 0x30 0x31`
|
|
* `version` allows forward compatibility
|
|
|
|
---
|
|
|
|
## 5. LogRecord Envelope
|
|
|
|
Each record is encoded as:
|
|
|
|
```c
|
|
#pragma pack(push,1)
|
|
typedef struct {
|
|
uint64_t logseq; // Monotonic sequence number
|
|
uint32_t record_type; // Record type tag
|
|
uint32_t payload_len; // Payload byte length
|
|
uint8_t payload[payload_len];
|
|
uint8_t record_hash[32]; // Hash-chained integrity (SHA-256)
|
|
} LogRecord;
|
|
#pragma pack(pop)
|
|
```
|
|
|
|
Hash chain rule (normative):
|
|
|
|
```
|
|
record_hash = H(prev_record_hash || logseq || record_type || payload_len || payload)
|
|
```
|
|
|
|
* `prev_record_hash` is the previous record's `record_hash`
|
|
* For the first record, `prev_record_hash` is 32 bytes of zero
|
|
* `H` is SHA-256 for v1
|
|
|
|
Readers MUST skip unknown `record_type` values using `payload_len` and MUST
|
|
continue replay without failure.
|
|
|
|
---
|
|
|
|
## 6. Record Type IDs (v1)
|
|
|
|
These type IDs bind the ASL/LOG/1 semantics to bytes-on-disk:
|
|
|
|
| Type ID | Record Type |
|
|
| ------- | ------------------ |
|
|
| 0x01 | SEGMENT_SEAL |
|
|
| 0x10 | TOMBSTONE |
|
|
| 0x11 | TOMBSTONE_LIFT |
|
|
| 0x20 | SNAPSHOT_ANCHOR |
|
|
| 0x30 | ARTIFACT_PUBLISH |
|
|
| 0x31 | ARTIFACT_UNPUBLISH |
|
|
|
|
---
|
|
|
|
## 6.1 Payload Schemas (v1)
|
|
|
|
All payloads are little-endian and packed. Variable-length fields are encoded
|
|
inline and accounted for by `payload_len`.
|
|
|
|
### 6.1.1 ArtifactRef
|
|
|
|
```c
|
|
#pragma pack(push,1)
|
|
typedef struct {
|
|
uint32_t hash_id; // Hash algorithm identifier
|
|
uint16_t digest_len; // Digest length in bytes
|
|
uint16_t reserved0; // Must be 0
|
|
uint8_t digest[digest_len];
|
|
} ArtifactRef;
|
|
#pragma pack(pop)
|
|
```
|
|
|
|
Notes:
|
|
|
|
* `digest_len` MUST be > 0.
|
|
* If StoreConfig fixes the hash, `digest_len` MUST match that hash's length.
|
|
|
|
### 6.1.2 SEGMENT_SEAL (Type 0x01)
|
|
|
|
```c
|
|
#pragma pack(push,1)
|
|
typedef struct {
|
|
uint64_t segment_id; // Store-local segment identifier
|
|
uint8_t segment_hash[32]; // SHA-256 over the segment file bytes
|
|
} SegmentSealPayload;
|
|
#pragma pack(pop)
|
|
```
|
|
|
|
### 6.1.3 TOMBSTONE (Type 0x10)
|
|
|
|
```c
|
|
#pragma pack(push,1)
|
|
typedef struct {
|
|
ArtifactRef artifact;
|
|
uint32_t scope; // Opaque to ASL/LOG/1
|
|
uint32_t reason_code; // Opaque to ASL/LOG/1
|
|
} TombstonePayload;
|
|
#pragma pack(pop)
|
|
```
|
|
|
|
### 6.1.4 TOMBSTONE_LIFT (Type 0x11)
|
|
|
|
```c
|
|
#pragma pack(push,1)
|
|
typedef struct {
|
|
ArtifactRef artifact;
|
|
uint64_t tombstone_logseq; // logseq of the tombstone being lifted
|
|
} TombstoneLiftPayload;
|
|
#pragma pack(pop)
|
|
```
|
|
|
|
### 6.1.5 SNAPSHOT_ANCHOR (Type 0x20)
|
|
|
|
```c
|
|
#pragma pack(push,1)
|
|
typedef struct {
|
|
uint64_t snapshot_id;
|
|
uint8_t root_hash[32]; // Hash of snapshot-visible state
|
|
} SnapshotAnchorPayload;
|
|
#pragma pack(pop)
|
|
```
|
|
|
|
### 6.1.6 ARTIFACT_PUBLISH (Type 0x30)
|
|
|
|
```c
|
|
#pragma pack(push,1)
|
|
typedef struct {
|
|
ArtifactRef artifact;
|
|
} ArtifactPublishPayload;
|
|
#pragma pack(pop)
|
|
```
|
|
|
|
### 6.1.7 ARTIFACT_UNPUBLISH (Type 0x31)
|
|
|
|
```c
|
|
#pragma pack(push,1)
|
|
typedef struct {
|
|
ArtifactRef artifact;
|
|
} ArtifactUnpublishPayload;
|
|
#pragma pack(pop)
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Versioning Rules
|
|
|
|
* `version = 1` for this specification.
|
|
* New record types MAY be added without bumping the version.
|
|
* Layout changes to `LogHeader` or `LogRecord` require a new version.
|
|
|
|
---
|
|
|
|
## 8. Relationship to Other Layers
|
|
|
|
| Layer | Responsibility |
|
|
| ---------------- | ------------------------------------------------ |
|
|
| ASL/LOG/1 | Semantic log behavior and replay rules |
|
|
| ASL-STORE-INDEX | Store lifecycle and snapshot/log contracts |
|
|
| ENC-ASL-LOG | Exact byte layout for log encoding (this doc) |
|
|
| ENC-ASL-CORE-INDEX | Exact byte layout for index segments |
|