Drop CBOR for simple custom manifest

This commit is contained in:
2026-05-09 12:30:30 -05:00
parent 343ecbf4c4
commit 6dd4c3e607
13 changed files with 939 additions and 863 deletions

118
AGENTS.md
View File

@@ -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: 1664 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: