refactor: drop alktype dependency; add BAST doc for chunk header

- Remove alktype from Cargo.toml (its only usage was a thin wrapper
  over jsonschema::options().build())
- Replace alktype::validation::build_validator with direct jsonschema
  in dispatch.rs
- Add docs/architecture/chunk-header.bast.json — the chunk header's
  BAST (Binary Abstract Syntax Tree) machine-readable wire spec
- Embed as channels::wire::CHUNK_HEADER_BAST via include_str! so
  downstream Rust crates can consume it without a file lookup
- Add test asserting the embedded BAST doc is valid JSON and matches
  the wire format
- Update AGENTS.md §10 and implementation-specialist.md: BAST docs
  are the contract; trivial/hot-path formats stay hand-rolled,
  complex formats use the alktype engine or codegen

Verification:
- cargo test: 543 passed, 0 failed
- cargo clippy --all-targets -- -D warnings: clean
- cargo fmt --check: clean
- cargo doc --no-deps: clean
- BAST doc compiles + round-trips against alktype v0.2.0 engine
This commit is contained in:
glm-5.2 committed 2026-08-17 06:08:13 +00:00
1 parent 08e7df2aa0
commit 44d4b496e8
10 files changed
+95 -42

No files matched your search

+44
View File
@@ -34,6 +34,17 @@ pub const MAX_CHUNK_LEN: u32 = 16 * 1024 * 1024;
/// without an explicit open op exchange.
pub const CHANNEL_ID_ZERO: u32 = 0;
/// The chunk header's BAST (Binary Abstract Syntax Tree) document —
/// the machine-readable wire-format spec. The canonical copy is
/// `docs/architecture/chunk-header.bast.json`; this const embeds it so
/// downstream Rust crates can consume it without a file lookup. BAST is
/// plain JSON consumable by any language; the `alktype` crate compiles
/// it into readers/writers/validators, and future codegen derives
/// language-specific implementations from it. The hand-rolled
/// [`parse_header`]/[`write_header`] functions are the hot path; the
/// BAST document is the contract.
pub const CHUNK_HEADER_BAST: &str = include_str!("../../docs/architecture/chunk-header.bast.json");
/// The parsed 8-byte chunk header.
///
/// `length = 0` is the EOF sentinel — the reassembled stream interprets
@@ -251,6 +262,39 @@ mod tests {
}
}
#[test]
fn chunk_header_bast_is_valid_json_and_describes_the_wire_format() {
let doc: serde_json::Value =
serde_json::from_str(CHUNK_HEADER_BAST).expect("BAST doc is valid JSON");
let def = doc
.get("$defs")
.and_then(|d| d.get("ChunkHeader"))
.expect("ChunkHeader def present");
assert_eq!(def.get("kind").and_then(|v| v.as_str()), Some("struct"));
assert_eq!(def.get("endian").and_then(|v| v.as_str()), Some("big"));
let fields = def
.get("fields")
.and_then(|v| v.as_array())
.expect("fields");
assert_eq!(fields.len(), 2);
assert_eq!(
fields[0].get("name").and_then(|v| v.as_str()),
Some("channel_id")
);
assert_eq!(
fields[0].get("kind").and_then(|v| v.as_str()),
Some("uint32")
);
assert_eq!(
fields[1].get("name").and_then(|v| v.as_str()),
Some("length")
);
assert_eq!(
fields[1].get("kind").and_then(|v| v.as_str()),
Some("uint32")
);
}
#[tokio::test]
async fn read_header_round_trips_through_duplex() {
let (mut reader, mut writer) = tokio::io::duplex(64);