Drop CBOR for simple custom manifest
This commit is contained in:
118
AGENTS.md
118
AGENTS.md
@@ -128,114 +128,18 @@ hash = SHA256("arboricx.merkle.node.v1" <> 0x00 <> serialized_node)
|
||||
|
||||
This is stored in SQLite via `ContentStore.hs`. Hash suffixes on identifiers (e.g., `foo_abc123...`) are validated: 16–64 hex characters (SHA256).
|
||||
|
||||
## 7. Arboricx Portable Wire Format
|
||||
## 7. Arboricx Portable Bundles (`.arboricx`)
|
||||
|
||||
The **Arboricx wire format** (module `Wire.hs`) defines a portable binary bundle for exchanging Tree Calculus terms, their Merkle DAGs, and associated metadata. It is versioned and schema-driven.
|
||||
Portable executable bundles are generated via `Wire.hs`. See `docs/arboricx-bundle-format.md` for the full binary format spec.
|
||||
|
||||
### Header
|
||||
```bash
|
||||
# Export a bundle from the content store
|
||||
./result/bin/tricu export -o myterm.arboricx myterm
|
||||
|
||||
# Run a bundle (requires TRICU_DB_PATH)
|
||||
./result/bin/tricu import -f lib/list.tri
|
||||
TRICU_DB_PATH=/tmp/tricu.db ./result/bin/tricu export -o list_ops.arboricx append
|
||||
```
|
||||
+------------------+-----------------+------------------+----------------+
|
||||
| Magic (8 bytes) | Major (2 bytes) | Minor (2 bytes) | Section Count |
|
||||
| | | | (4 bytes) |
|
||||
+------------------+-----------------+------------------+----------------+
|
||||
| Flags (8 bytes) | Dir Offset (8 bytes)
|
||||
+------------------+-----------------+------------------+
|
||||
```
|
||||
|
||||
- **Magic**: `ARBORICX` (`0x41 0x52 0x42 0x4f 0x52 0x49 0x43 0x58`)
|
||||
- **Header length**: 32 bytes
|
||||
- **Major version**: `1` | **Minor version**: `0`
|
||||
|
||||
### Section Directory
|
||||
|
||||
Immediately follows the header. Each section entry is 60 bytes:
|
||||
|
||||
```
|
||||
+------------------+------------------+-----------------+------------------+
|
||||
| Type (4 bytes) | Version (2 bytes)| Flags (2 bytes) | Compression (2) |
|
||||
+------------------+------------------+-----------------+------------------+
|
||||
| Digest Algo (2) | Offset (8 bytes) | Length (8 bytes)| SHA256 digest (32)|
|
||||
+------------------+------------------+-----------------+------------------+
|
||||
```
|
||||
|
||||
Known section types:
|
||||
|
||||
| Type | Name | Required | Description |
|
||||
|------|-----------|----------|-------------|
|
||||
| 1 | manifest | Yes | JSON manifest metadata |
|
||||
| 2 | nodes | Yes | Binary Merkle node payloads |
|
||||
|
||||
### Section 1 — Manifest (JSON)
|
||||
|
||||
The manifest describes the bundle's semantics, exports, and schema. Key fields:
|
||||
|
||||
| Field | Value | Description |
|
||||
|-------|-------|-------------|
|
||||
| `schema` | `"arboricx.bundle.manifest.v1"` | Manifest schema version |
|
||||
| `bundleType` | `"tree-calculus-executable-object"` | Bundle category |
|
||||
| `tree.calculus` | `"tree-calculus.v1"` | Tree calculus version |
|
||||
| `tree.nodeHash.algorithm` | `"sha256"` | Hash algorithm |
|
||||
| `tree.nodeHash.domain` | `"arboricx.merkle.node.v1"` | Hash domain string |
|
||||
| `tree.nodePayload` | `"arboricx.merkle.payload.v1"` | Payload encoding |
|
||||
| `runtime.semantics` | `"tree-calculus.v1"` | Evaluation semantics |
|
||||
| `runtime.abi` | `"arboricx.abi.tree.v1"` | Runtime ABI |
|
||||
| `closure` | `"complete"` | Bundle must be a complete DAG |
|
||||
| `roots` | `[{"hash": "...", "role": "..."}]` | Named root hashes |
|
||||
| `exports` | `[{"name": "...", "root": "..."}]` | Export aliases for roots |
|
||||
| `metadata.createdBy` | `"arboricx"` | Originator |
|
||||
|
||||
### Section 2 — Nodes (Binary)
|
||||
|
||||
```
|
||||
+------------------+-------------------+-------------------+-----------------+
|
||||
| Node Count (8) | Hash (32 bytes) | Payload Len (4) | Payload (N) |
|
||||
+------------------+-------------------+-------------------+-----------------+
|
||||
```
|
||||
|
||||
Each node entry contains:
|
||||
- 32-byte Merkle hash (hex-encoded in identifiers, raw in binary)
|
||||
- 4-byte big-endian payload length
|
||||
- N bytes of serialized node payload (`0x00` for Leaf, `0x01 || hash` for Stem, `0x02 || left || right` for Fork)
|
||||
|
||||
### Bundle verification flow
|
||||
|
||||
1. Check magic bytes
|
||||
2. Validate major version
|
||||
3. Parse section directory
|
||||
4. For each section: verify SHA256 digest against actual bytes
|
||||
5. Decode JSON manifest
|
||||
6. Decode binary node entries into Merkle DAG
|
||||
7. Verify all root hashes present in manifest exist in node map
|
||||
8. Verify export root hashes present
|
||||
9. Verify children references are complete (no dangling nodes)
|
||||
10. Reject unknown critical sections
|
||||
|
||||
### Data types (Wire.hs)
|
||||
|
||||
| Type | Purpose |
|
||||
|------|---------|
|
||||
| `Bundle` | Top-level bundle: version, roots, nodes map, manifest |
|
||||
| `BundleManifest` | JSON metadata: schema, tree spec, runtime spec, roots, exports |
|
||||
| `TreeSpec` | Tree calculus version + hash algorithm + payload encoding |
|
||||
| `NodeHashSpec` | Hash algorithm and domain string |
|
||||
| `RuntimeSpec` | Semantics, evaluation order, ABI, capabilities |
|
||||
| `BundleRoot` | Root hash + role (`"default"` or `"root"`) |
|
||||
| `BundleExport` | Export name + root hash + kind + ABI |
|
||||
| `BundleMetadata` | Optional package, version, description, license, createdBy |
|
||||
| `ClosureMode` | `ClosureComplete` or `ClosurePartial` |
|
||||
|
||||
### Key functions
|
||||
|
||||
| Function | Signature | Purpose |
|
||||
|----------|-----------|---------|
|
||||
| `encodeBundle` | `Bundle → ByteString` | Serialize bundle to wire bytes |
|
||||
| `decodeBundle` | `ByteString → Either String Bundle` | Parse wire bytes into Bundle |
|
||||
| `verifyBundle` | `Bundle → Either String ()` | Validate DAG, manifest, roots |
|
||||
| `collectReachableNodes` | `Connection → MerkleHash → IO [(MerkleHash, ByteString)]` | Traverse DAG from root |
|
||||
| `exportBundle` | `Connection → [MerkleHash] → IO ByteString` | Build bundle from content store |
|
||||
| `exportNamedBundle` | `Connection → [(Text, MerkleHash)] → IO ByteString` | Build with named roots |
|
||||
| `importBundle` | `Connection → ByteString → IO [MerkleHash]` | Import bundle into content store |
|
||||
|
||||
## 8. Directory Layout
|
||||
|
||||
@@ -273,12 +177,12 @@ tricu/
|
||||
## 9. JS Arboricx Runtime
|
||||
|
||||
A JavaScript implementation of the Arboricx portable bundle runtime lives in `ext/js/`.
|
||||
It is a reference implementation — not a tricu source parser. It reads `.tri.bundle` files produced by the Haskell toolchain, verifies Merkle node hashes, reconstructs tree values, and reduces them.
|
||||
It is a reference implementation — not a tricu source parser. It reads `.arboricx` files produced by the Haskell toolchain, verifies Merkle node hashes, reconstructs tree values, and reduces them.
|
||||
|
||||
From project root:
|
||||
```bash
|
||||
node ext/js/src/cli.js inspect test/fixtures/id.tri.bundle
|
||||
node ext/js/src/cli.js run test/fixtures/true.tri.bundle
|
||||
node ext/js/src/cli.js inspect test/fixtures/id.arboricx
|
||||
node ext/js/src/cli.js run test/fixtures/true.arboricx
|
||||
```
|
||||
|
||||
The JS runtime implements:
|
||||
|
||||
Reference in New Issue
Block a user